<commit_before>extern crate rand;

use rand::{weak_rng, XorShiftRng, Rng};
use std::fmt;
use std::fmt::{Formatter, Debug};

trait Specimen: Sized {
    fn evaluate(&self) -> f32;
    fn mutate(generation: &mut[Self]);
    fn procrastinate(parents: &[Self]) -> Self;
    fn filter_strongest(species: &mut Vec<Self>);

    fn initial() -> Vec<Self>;
}

fn genetic<S: Specimen>(threshold: f32, max_iters: usize, nparents: usize) -> S {
    let mut species: Vec<S> = S::initial();
    let mut best = (0f32, 0);
    for _ in 0..max_iters {
        species = next_gen(species, nparents);

        for (i, specimen) in species.iter().enumerate() {
            let score = specimen.evaluate();
            if best.0 <= score {
                best = (score, i)
            }
        }

        if best.0 >= threshold {
            println!("found!");
            break;
        }
    }

    species.swap_remove(best.1)
}

fn next_gen<S: Specimen>(mut species: Vec<S>, nparents: usize) -> Vec<S> {
    // 1. filter strongest
    S::filter_strongest(&mut species);

    // 2. bear children
    let families = partition(species, nparents);
    let mut species = vec![];
    let mut children = vec![];
    for family in families.into_iter() {
        if family.len() > 1 {
            let child = S::procrastinate(&family);
            children.push(child);
        }
        species.extend(family)
    }

    // 3. mutate
    S::mutate(&mut children);

    species.extend(children);

    species
}

fn partition<S: Specimen>(mut species: Vec<S>, nparents: usize) -> Vec<Vec<S>> {
    let mut families = vec![];
    let mut family = vec![];
    let mut rng = weak_rng();
    let mut j = 0;
    for _ in 0..species.len() {
        let next = rng.gen_range(0, species.len());
        let s = species.swap_remove(next);
        family.push(s);

        j += 1;
        if j == nparents {
            j = 0;
            families.push(family);
            family = vec![];
        }
    }

    if !family.is_empty() {
        families.push(family);
    }

    families
}

//---------------------------------------------------

// BEST FOR SIZE=8
//const SIZE: usize = 8;
//const MUTATION_PROBABILITY: f32 = 0.01f32;
//const POPULATION: usize = 500;
//const MAX_ITERS: usize = 100000;
//const NPARENTS: usize = 3;

//const SIZE: usize = 12;
//const MUTATION_PROBABILITY: f32 = 0.01f32;
//const POPULATION: usize = 1000;
//const MAX_ITERS: usize = 100000;
//const NPARENTS: usize = 3;

const SIZE: usize = 12;
const MUTATION_PROBABILITY: f32 = 0.001f32;
const POPULATION: usize = 2000;
const MAX_ITERS: usize = 100000;
const NPARENTS: usize = 3;

struct Board {
    score: f32,
    queens: Vec<(usize, usize)>,
    cells: Vec<bool>
}

impl Board {
    fn new(n: usize, queens: Vec<(usize, usize)>) -> Board {
        let mut cells = vec![false; n*n];
        for &(ref x, ref y) in queens.iter() {
            cells[n*y + x] = true;
        }

        let mut board = Board { score: 0f32, queens: queens, cells: cells };
        board.reevaluate();
        board
    }

//    fn n(&self) -> usize {
//        SIZE
//    }

    fn at(&mut self, x: usize, y: usize) -> &mut bool {
//        let n = self.n();
        &mut self.cells[SIZE * y + x]
    }

    fn reevaluate(&mut self) {
        let mut score: usize = 0;
        let mut conflicts = vec![0; SIZE];
        for i in 0 .. self.queens.len() {
            self.eval_conflicts(i, &mut conflicts);

            if conflicts[i] == 0 {
                score += 1;
            }
        }

        self.score = score as f32 + 0.000001;
    }

    fn do_mutate(&mut self, rng: &mut XorShiftRng) {
        let q = rng.gen_range(0, SIZE);
        loop {
            let x = rng.gen_range(0, SIZE);
            let y = rng.gen_range(0, SIZE);
            if !*self.at(x, y) {
                let (oldx, oldy) = self.queens[q].clone();
                *self.at(oldx, oldy) = false;
                *self.at(x, y) = true;
                self.queens[q] = (x, y);
                self.reevaluate();
                break;
            }
        }
    }

    fn eval_conflicts(&self, q1: usize, conflicts: &mut [usize]) {
        let &(ref x1, ref y1) = &self.queens[q1];

        for q2 in q1+1..SIZE {
            let &(ref x2, ref y2) = &self.queens[q2];
            if Self::conflict(*x1, *y1, *x2, *y2) {
                conflicts[q1] += 1;
                conflicts[q2] += 1;
            }
        }
    }

    fn conflict(x1: usize, y1: usize, x2: usize, y2: usize) -> bool {
        x1 == x2
            || y1 == y2
            || x1.wrapping_sub(x2) == y1.wrapping_sub(y2)
            || x1.wrapping_sub(x2) == y2.wrapping_sub(y1)
    }
}

impl Specimen for Board {

    fn evaluate(&self) -> f32 {
        self.score
    }

    fn mutate(generation: &mut [Self]) {
        let mut rng = weak_rng();
        for board in generation.iter_mut() {
            if rng.next_f32() < MUTATION_PROBABILITY {
                board.do_mutate(&mut rng);
            }
        }
    }

    fn procrastinate(parents: &[Self]) -> Self {
        let mut rng = weak_rng();
        let nqueens = parents.len() * SIZE;

        let mut child = Board::new(SIZE, vec![]);

        let mut all_queens = (0..nqueens).collect::<Vec<_>>();

        loop {
            let next = rng.gen_range(0, all_queens.len());
            let mut queen = all_queens.swap_remove(next);
            let parent = queen/SIZE;
            queen %= SIZE;

            let (x,y) = parents[parent].queens[queen].clone();
            if !*child.at(x, y) {
                child.queens.push((x, y));
                *child.at(x, y) = true;
                if child.queens.len() == SIZE {
                    break;
                }
            }
        }

        child.reevaluate();
        child
    }

    fn filter_strongest(species: &mut Vec<Self>) {
        if species.len() <= POPULATION {
            return;
        }

        species.sort_by(|s, t| t.score.partial_cmp(&s.score).unwrap());
        species.truncate(POPULATION);
    }

    fn initial() -> Vec<Self> {
        let mut rng = weak_rng();
        let mut boards = Vec::with_capacity(POPULATION);

        for i in 0..POPULATION {
            let mut board = Board::new(SIZE, vec![]);

            loop {
                let x = rng.gen_range(0, SIZE);
                let y = rng.gen_range(0, SIZE);
                if !*board.at(x, y) {
                    board.queens.push((x, y));
                    *board.at(x, y) = true;
                    if board.queens.len() == SIZE {
                        break;
                    }
                }
            }

            board.reevaluate();
            boards.push(board);
        }

        boards
    }
}

impl Debug for Board {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "score={}, queens=[{:?}]", self.score, self.queens)
    }
}

fn genetic_queens() {
    let best = genetic::<Board>(SIZE as f32, MAX_ITERS, NPARENTS);
    println!("best: {:?}", &best);
}

fn main() {
    genetic_queens()
}

<commit_msg>reevaluate each child only once<commit_after>extern crate rand;

use rand::{weak_rng, XorShiftRng, Rng};
use std::fmt;
use std::fmt::{Formatter, Debug};

trait Specimen: Sized {
    fn score(&self) -> f32;
    fn reevaluate(&mut self);
    fn mutate(generation: &mut[Self]);
    fn procrastinate(parents: &[Self]) -> Self;
    fn filter_strongest(species: &mut Vec<Self>);

    fn initial() -> Vec<Self>;
}

fn genetic<S: Specimen>(threshold: f32, max_iters: usize, nparents: usize) -> S {
    let mut species: Vec<S> = S::initial();
    let mut best = (0f32, 0);
    for _ in 0..max_iters {
        species = next_gen(species, nparents);

        for (i, specimen) in species.iter().enumerate() {
            let score = specimen.score();
            if best.0 <= score {
                best = (score, i)
            }
        }

        if best.0 >= threshold {
            println!("found!");
            break;
        }
    }

    species.swap_remove(best.1)
}

fn next_gen<S: Specimen>(mut species: Vec<S>, nparents: usize) -> Vec<S> {
    // 1. filter strongest
    S::filter_strongest(&mut species);

    // 2. bear children
    let families = partition(species, nparents);
    let mut species = vec![];
    let mut children = vec![];
    for family in families.into_iter() {
        if family.len() > 1 {
            let child = S::procrastinate(&family);
            children.push(child);
        }
        species.extend(family)
    }

    // 3. mutate
    S::mutate(&mut children);
    for child in children.iter_mut() {
        child.reevaluate();
    }

    species.extend(children);

    species
}

fn partition<S: Specimen>(mut species: Vec<S>, nparents: usize) -> Vec<Vec<S>> {
    let mut families = vec![];
    let mut family = vec![];
    let mut rng = weak_rng();
    let mut j = 0;
    for _ in 0..species.len() {
        let next = rng.gen_range(0, species.len());
        let s = species.swap_remove(next);
        family.push(s);

        j += 1;
        if j == nparents {
            j = 0;
            families.push(family);
            family = vec![];
        }
    }

    if !family.is_empty() {
        families.push(family);
    }

    families
}

//---------------------------------------------------

// BEST FOR SIZE=8
//const SIZE: usize = 8;
//const MUTATION_PROBABILITY: f32 = 0.01f32;
//const POPULATION: usize = 500;
//const MAX_ITERS: usize = 100000;
//const NPARENTS: usize = 3;

//const SIZE: usize = 12;
//const MUTATION_PROBABILITY: f32 = 0.01f32;
//const POPULATION: usize = 1000;
//const MAX_ITERS: usize = 100000;
//const NPARENTS: usize = 3;

const SIZE: usize = 12;
const MUTATION_PROBABILITY: f32 = 0.001f32;
const POPULATION: usize = 2000;
const MAX_ITERS: usize = 100000;
const NPARENTS: usize = 3;

struct Board {
    score: f32,
    queens: Vec<(usize, usize)>,
    cells: Vec<bool>
}

impl Board {
    fn new(n: usize, queens: Vec<(usize, usize)>) -> Board {
        let mut cells = vec![false; n*n];
        for &(ref x, ref y) in queens.iter() {
            cells[n*y + x] = true;
        }

        Board { score: 0f32, queens: queens, cells: cells }
    }

//    fn n(&self) -> usize {
//        SIZE
//    }

    fn at(&mut self, x: usize, y: usize) -> &mut bool {
//        let n = self.n();
        &mut self.cells[SIZE * y + x]
    }

    fn do_mutate(&mut self, rng: &mut XorShiftRng) {
        let q = rng.gen_range(0, SIZE);
        loop {
            let x = rng.gen_range(0, SIZE);
            let y = rng.gen_range(0, SIZE);
            if !*self.at(x, y) {
                let (oldx, oldy) = self.queens[q].clone();
                *self.at(oldx, oldy) = false;
                *self.at(x, y) = true;
                self.queens[q] = (x, y);
//                self.reevaluate();
                break;
            }
        }
    }

    fn eval_conflicts(&self, q1: usize, conflicts: &mut [usize]) {
        let &(ref x1, ref y1) = &self.queens[q1];

        for q2 in q1+1..SIZE {
            let &(ref x2, ref y2) = &self.queens[q2];
            if Self::conflict(*x1, *y1, *x2, *y2) {
                conflicts[q1] += 1;
                conflicts[q2] += 1;
            }
        }
    }

    fn conflict(x1: usize, y1: usize, x2: usize, y2: usize) -> bool {
        x1 == x2
            || y1 == y2
            || x1.wrapping_sub(x2) == y1.wrapping_sub(y2)
            || x1.wrapping_sub(x2) == y2.wrapping_sub(y1)
    }
}

impl Specimen for Board {
    fn reevaluate(&mut self) {
        let mut score: usize = 0;
        let mut conflicts = vec![0; SIZE];
        for i in 0 .. self.queens.len() {
            self.eval_conflicts(i, &mut conflicts);

            if conflicts[i] == 0 {
                score += 1;
            }
        }

        self.score = score as f32 + 0.000001;
    }

    fn score(&self) -> f32 {
        self.score
    }

    fn mutate(new_gen: &mut [Self]) {
        let mut rng = weak_rng();
        for board in new_gen.iter_mut() {
            if rng.next_f32() < MUTATION_PROBABILITY {
                board.do_mutate(&mut rng);
            }
        }
    }

    fn procrastinate(parents: &[Self]) -> Self {
        let mut rng = weak_rng();
        let nqueens = parents.len() * SIZE;

        let mut child = Board::new(SIZE, vec![]);

        let mut all_queens = (0..nqueens).collect::<Vec<_>>();

        loop {
            let next = rng.gen_range(0, all_queens.len());
            let mut queen = all_queens.swap_remove(next);
            let parent = queen/SIZE;
            queen %= SIZE;

            let (x,y) = parents[parent].queens[queen].clone();
            if !*child.at(x, y) {
                child.queens.push((x, y));
                *child.at(x, y) = true;
                if child.queens.len() == SIZE {
                    break;
                }
            }
        }

        child
    }

    fn filter_strongest(species: &mut Vec<Self>) {
        if species.len() <= POPULATION {
            return;
        }

        species.sort_by(|s, t| t.score.partial_cmp(&s.score).unwrap());
        species.truncate(POPULATION);
    }

    fn initial() -> Vec<Self> {
        let mut rng = weak_rng();
        let mut boards = Vec::with_capacity(POPULATION);

        for _ in 0..POPULATION {
            let mut board = Board::new(SIZE, vec![]);

            loop {
                let x = rng.gen_range(0, SIZE);
                let y = rng.gen_range(0, SIZE);
                if !*board.at(x, y) {
                    board.queens.push((x, y));
                    *board.at(x, y) = true;
                    if board.queens.len() == SIZE {
                        break;
                    }
                }
            }

            board.reevaluate();
            boards.push(board);
        }

        boards
    }
}

impl Debug for Board {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "score={}, queens=[{:?}]", self.score, self.queens)
    }
}

fn genetic_queens() {
    let best = genetic::<Board>(SIZE as f32, MAX_ITERS, NPARENTS);
    println!("best: {:?}", &best);
}

fn main() {
    genetic_queens()
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate termios;

use libc::STDIN_FILENO;
use termios::{Termios, tcsetattr, TCSAFLUSH};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Read};

struct TermReset {
    orig_term: Termios
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

fn iscntrl(c: u8) -> bool {
    unsafe {
        libc::iscntrl(c as i32) != 0
    }
}

fn main() {
    let _reset = enable_raw_mode().unwrap();

    let mut stdin = io::stdin();
    let mut buf = [0; 1];

    while let Ok(1) = stdin.read(&mut buf) {
        let c = buf[0];
        if c == b'q' {
            break;
        }
        if iscntrl(c) {
            print!("{}\r\n", &c);
        } else {
            print!("{} ({})\r\n", &c, c as char);
        }
    }
}
<commit_msg>read() with timeout<commit_after>extern crate libc;
extern crate termios;

use libc::STDIN_FILENO;
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Read, ErrorKind};

struct TermReset {
    orig_term: Termios
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

fn iscntrl(c: u8) -> bool {
    unsafe {
        libc::iscntrl(c as i32) != 0
    }
}

fn main() {
    let _reset = enable_raw_mode().unwrap();

    let mut stdin = io::stdin();
    let mut buf = [0; 1];

    loop {
        buf[0] = 0;
        let n = stdin.read(&mut buf)
                     .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                     .expect("read");
        if n > 0 {
            let c = buf[0];
            if c == b'q' {
                break;
            }
            if iscntrl(c) {
                print!("{}\r\n", &c);
            } else {
                print!("{} ({})\r\n", &c, c as char);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
#[macro_use]
extern crate clap;
extern crate image;

use std::path::Path;
use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

arg_enum!{
    enum Mode {
        Brute
    }
}

fn main() {
    let matches = App::new("asami")
        .version("0.1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .args_from_usage(
            "<INPUT> 'The input file to use'
             <OUTPUT> 'The output file to use'")
        .arg(Arg::from_usage("-m --mode <MODE> 'The mode to use'")
            .possible_values(&Mode::variants())
            .default_value("Brute"))
        .arg(Arg::from_usage("--min <MIN> 'The minimum chunk size to sort'")
            .default_value("32"))
        .arg(Arg::from_usage("--max <MAX> 'The maximum chunk size to sort'")
            .default_value("64"))
        .get_matches();

    let input = matches.value_of("INPUT").unwrap();
    let output = matches.value_of("OUTPUT").unwrap();

    let min = value_t!(matches, "min", u32).expect("the minimum chunk size has to be a number");
    let max = value_t!(matches, "max", u32).expect("the maximum chunk size has to be a number");

    let mode = matches.value_of("mode").unwrap();

    println!("mode: {}", mode);

    handle_request(input, output, min, max);
}

fn handle_request(input: &str, output: &str, chunk_min_length: u32, chunk_max_length: u32) {
    println!("input: {}, output: {}", input, output);
    println!("minimum chunk size: {}, maximum chunk size: {}", chunk_min_length, chunk_max_length);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    println!("dimensions {:?}", in_img.dimensions());
    println!("{:?}", in_img.color());

    let out_img = brute_sort(in_img, chunk_min_length, chunk_max_length);

    let _ = out_img.save(output).unwrap();
}

fn brute_sort(input: &DynamicImage, chunk_min_length: u32, chunk_max_length: u32) -> RgbaImage {
    let mut output = RgbaImage::new(input.width(), input.height());

    let mut out_x = 0;
    let mut out_y = 0;

    let mut tmp = Vec::new();

    let mut threshold = calculate_chunk_threshold(chunk_min_length, chunk_max_length);

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() == threshold as usize {
            tmp.sort_by(|a, b| (a[2]).cmp(&b[2]));
            write_pixels_to_image(&mut output, out_x, out_y, &mut tmp);
            increase_coordinates(&mut out_x, &mut out_y, threshold, &output);
            threshold = calculate_chunk_threshold(chunk_min_length, chunk_max_length);
        }
    }
    write_pixels_to_image(&mut output, out_x, out_y, &mut tmp);
    output
}

fn calculate_chunk_threshold(chunk_min_length: u32, chunk_max_length: u32) -> u32 {
    rand::thread_rng().gen_range(chunk_min_length, chunk_max_length + 1)
}

fn increase_coordinates(x: &mut u32, y: &mut u32, steps: u32, image: &RgbaImage) {
    *y = *y + (*x + steps) / image.width();
    *x = (*x + steps) % image.width();
}

fn write_pixels_to_image(image: &mut RgbaImage, x: u32, y: u32, pixels: &mut Vec<image::Rgba<u8>>){
    let mut x = x;
    let mut y = y;

    while !pixels.is_empty() {
        image.put_pixel(x, y, pixels.pop().unwrap());
        increase_coordinates(&mut x, &mut y, 1, &image);
    }
}
<commit_msg>better cli output<commit_after>extern crate rand;
#[macro_use]
extern crate clap;
extern crate image;

use std::path::Path;
use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

arg_enum!{
    enum Mode {
        Brute
    }
}

fn main() {
    let matches = App::new("asami")
        .version("0.1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .args_from_usage(
            "<INPUT> 'The input file to use'
             <OUTPUT> 'The output file to use'")
        .arg(Arg::from_usage("-m --mode <MODE> 'The mode to use'")
            .possible_values(&Mode::variants())
            .default_value("Brute"))
        .arg(Arg::from_usage("--min <MIN> 'The minimum chunk size to sort'")
            .default_value("32"))
        .arg(Arg::from_usage("--max <MAX> 'The maximum chunk size to sort'")
            .default_value("64"))
        .get_matches();

    let input = matches.value_of("INPUT").unwrap();
    let output = matches.value_of("OUTPUT").unwrap();

    let min = value_t!(matches, "min", u32).expect("the minimum chunk size has to be a number");
    let max = value_t!(matches, "max", u32).expect("the maximum chunk size has to be a number");

    let mode = matches.value_of("mode").unwrap();

    println!("mode: {}", mode);

    handle_request(input, output, min, max);
}

fn handle_request(input: &str, output: &str, chunk_min_length: u32, chunk_max_length: u32) {
    println!("input: {}, output: {}", input, output);
    println!("minimum chunk size: {}, maximum chunk size: {}", chunk_min_length, chunk_max_length);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    println!("dimensions: {:?}", in_img.dimensions());
    println!("colour: {:?}", in_img.color());

    let out_img = brute_sort(in_img, chunk_min_length, chunk_max_length);

    let _ = out_img.save(output).unwrap();
}

fn brute_sort(input: &DynamicImage, chunk_min_length: u32, chunk_max_length: u32) -> RgbaImage {
    let mut output = RgbaImage::new(input.width(), input.height());

    let mut out_x = 0;
    let mut out_y = 0;

    let mut tmp = Vec::new();

    let mut threshold = calculate_chunk_threshold(chunk_min_length, chunk_max_length);

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() == threshold as usize {
            tmp.sort_by(|a, b| (a[2]).cmp(&b[2]));
            write_pixels_to_image(&mut output, out_x, out_y, &mut tmp);
            increase_coordinates(&mut out_x, &mut out_y, threshold, &output);
            threshold = calculate_chunk_threshold(chunk_min_length, chunk_max_length);
        }
    }
    write_pixels_to_image(&mut output, out_x, out_y, &mut tmp);
    output
}

fn calculate_chunk_threshold(chunk_min_length: u32, chunk_max_length: u32) -> u32 {
    rand::thread_rng().gen_range(chunk_min_length, chunk_max_length + 1)
}

fn increase_coordinates(x: &mut u32, y: &mut u32, steps: u32, image: &RgbaImage) {
    *y = *y + (*x + steps) / image.width();
    *x = (*x + steps) % image.width();
}

fn write_pixels_to_image(image: &mut RgbaImage, x: u32, y: u32, pixels: &mut Vec<image::Rgba<u8>>){
    let mut x = x;
    let mut y = y;

    while !pixels.is_empty() {
        image.put_pixel(x, y, pixels.pop().unwrap());
        increase_coordinates(&mut x, &mut y, 1, &image);
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;
#[macro_use]
extern crate clap;

use clap::{Arg, App};

fn main() {
    App::new("Helium")
        .version(crate_version!())
        .author(crate_authors!())
        .about("The awesomest of editors.")
        .arg(Arg::with_name("file")
            .help("Input file")
            .index(1))
        .get_matches();

    let sdl_context = sdl2::init().unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();
    let window = sdl_context.video()
        .unwrap()
        .window("Helium", 800, 600)
        .resizable()
        .allow_highdpi()
        .build()
        .unwrap();
    let mut renderer = window.renderer()
        .accelerated()
        .present_vsync()
        .build()
        .unwrap();
    let font = ttf_context.load_font(std::path::Path::new("DejaVuSansMono.ttf"), 16).unwrap();
    let hello =
        font.render("Hello world!").blended(sdl2::pixels::Color::RGB(150, 150, 150)).unwrap();
    let mut hello_texture = renderer.create_texture_from_surface(&hello).unwrap();
    renderer.set_draw_color(sdl2::pixels::Color::RGB(30, 35, 40));

    for event in sdl_context.event_pump().unwrap().wait_iter() {
        match event {
            sdl2::event::Event::Quit { .. } => return,
            sdl2::event::Event::Window { .. } => {
                renderer.clear();
                renderer.copy(&mut hello_texture, None, None).unwrap();
                renderer.present();
            }
            _ => {}
        }
    }
}
<commit_msg>Render proper text dimensions<commit_after>extern crate sdl2;
#[macro_use]
extern crate clap;

use clap::{Arg, App};

fn main() {
    App::new("Helium")
        .version(crate_version!())
        .author(crate_authors!())
        .about("The awesomest of editors.")
        .arg(Arg::with_name("file")
            .help("Input file")
            .index(1))
        .get_matches();

    let sdl_context = sdl2::init().unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();
    let window = sdl_context.video()
        .unwrap()
        .window("Helium", 800, 600)
        .resizable()
        .allow_highdpi()
        .build()
        .unwrap();
    let mut renderer = window.renderer()
        .accelerated()
        .present_vsync()
        .build()
        .unwrap();
    let font = ttf_context.load_font(std::path::Path::new("DejaVuSansMono.ttf"), 16).unwrap();
    let hello =
        font.render("Hello world!").blended(sdl2::pixels::Color::RGB(150, 150, 150)).unwrap();
    let rect = sdl2::rect::Rect::new(0, 0, hello.width(), hello.height());
    let mut hello_texture = renderer.create_texture_from_surface(&hello).unwrap();
    renderer.set_draw_color(sdl2::pixels::Color::RGB(30, 35, 40));

    for event in sdl_context.event_pump().unwrap().wait_iter() {
        match event {
            sdl2::event::Event::Quit { .. } => return,
            sdl2::event::Event::Window { .. } => {
                renderer.clear();
                renderer.copy(&mut hello_texture, None, Some(rect)).unwrap();
                renderer.present();
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>use ct_tools::common::{sha256_hex, Log};
use ct_tools::crtsh;
use ct_tools::ct::submit_cert_to_logs;
use ct_tools::google::{fetch_all_ct_logs, fetch_trusted_ct_logs};
use futures::stream::{StreamExt, TryStreamExt};
use rustls::Session;
use std::fs::{self, File};
use std::io::Read;
use std::net::SocketAddr;
use std::process::Stdio;
use std::sync::Arc;
use std::time::Duration;
use structopt::StructOpt;
use tokio::io::AsyncWriteExt;
use tokio::process::Command;

fn pems_to_chain(data: &[u8]) -> Vec<Vec<u8>> {
    pem::parse_many(data)
        .into_iter()
        .filter(|p| p.tag == "CERTIFICATE")
        .map(|p| p.contents)
        .collect()
}

fn compute_paths(paths: &[String]) -> Vec<String> {
    paths
        .iter()
        .flat_map(|p| {
            if fs::metadata(p).unwrap().is_dir() {
                fs::read_dir(p)
                    .unwrap()
                    .map(|d| d.unwrap().path().to_str().unwrap().to_string())
                    .collect()
            } else {
                vec![p.clone()]
            }
        })
        .collect()
}

async fn submit(paths: &[String], all_logs: bool) {
    let http_client = reqwest::Client::new();

    let logs = if all_logs {
        fetch_all_ct_logs(&http_client).await
    } else {
        fetch_trusted_ct_logs(&http_client).await
    };

    let all_paths = compute_paths(paths);

    let work = futures::stream::iter(all_paths.iter().map(|path| {
        let path = path.to_string();
        let mut contents = Vec::new();
        File::open(&path)
            .unwrap()
            .read_to_end(&mut contents)
            .unwrap();

        let http_client = &http_client;
        let logs = &logs;
        let mut chain = pems_to_chain(&contents);
        async move {
            if chain.len() == 1 {
                // TODO: There's got to be some way to do this ourselves, instead of using crt.sh
                // as a glorified AIA chaser.
                println!(
                    "[{}] Only one certificate in chain, using crt.sh to build a full chain ...",
                    &path
                );
                let new_chain = crtsh::build_chain_for_cert(&http_client, &chain[0]).await;
                chain = match new_chain {
                    Ok(c) => c,
                    Err(()) => {
                        println!("[{}] Unable to build a chain", path);
                        return;
                    }
                }
            }
            println!("[{}] Submitting ...", &path);
            let timeout = Duration::from_secs(30);
            let scts = submit_cert_to_logs(&http_client, &logs, &chain, timeout).await;

            if !scts.is_empty() {
                println!(
                    "[{}] Find the cert on crt.sh: {}",
                    path,
                    crtsh::url_for_cert(&chain[0])
                );
                let mut table = prettytable::Table::new();
                table.add_row(prettytable::Row::new(vec![prettytable::Cell::new("Log")]));
                for (log_idx, _) in scts {
                    let log = &logs[log_idx];
                    table.add_row(prettytable::Row::new(vec![prettytable::Cell::new(
                        &log.description,
                    )]));
                }
                table.printstd();
                println!();
                println!();
            } else {
                println!("[{}] No SCTs obtained", &path);
            }
        }
    }))
    .buffer_unordered(4)
    .for_each(|_| async {});
    work.await;
}

async fn check(paths: &[String]) {
    let http_client = reqwest::Client::new();

    let all_paths = compute_paths(paths);

    let work = futures::stream::iter(all_paths.iter().map(|path| {
        let path = path.to_string();
        let mut contents = Vec::new();
        File::open(&path)
            .unwrap()
            .read_to_end(&mut contents)
            .unwrap();

        let http_client = &http_client;
        let chain = pems_to_chain(&contents);
        async move {
            if !chain.is_empty() && crtsh::is_cert_logged(&http_client, &chain[0]).await {
                println!("{} was already logged", path);
            } else {
                println!("{} has not been logged", path);
            }
        }
    }))
    .buffer_unordered(16)
    .for_each(|_| async {});
    work.await;
}

async fn handle_request(
    request: hyper::Request<hyper::Body>,
    templates: Arc<tera::Tera>,
    http_client: Arc<reqwest::Client>,
    logs: Arc<[Log]>,
    client_cert: Option<rustls::Certificate>,
) -> Result<hyper::Response<hyper::Body>, hyper::Error> {
    let mut crtsh_url = None;
    let mut rendered_cert = None;
    if let Some(cert) = client_cert {
        if request.method() == hyper::Method::POST {
            if let Ok(chain) = crtsh::build_chain_for_cert(&http_client, &cert.0).await {
                let timeout = Duration::from_secs(5);
                let scts = submit_cert_to_logs(&http_client, &logs, &chain, timeout).await;
                if !scts.is_empty() {
                    crtsh_url = Some(crtsh::url_for_cert(&chain[0]));
                    println!("Successfully submitted: {}", sha256_hex(&chain[0]));
                }
            }
        }

        let mut process = Command::new("openssl")
            .arg("x509")
            .arg("-text")
            .arg("-noout")
            .arg("-inform")
            .arg("der")
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .unwrap();
        let cert_bytes = cert.0.clone();
        AsyncWriteExt::write_all(&mut process.stdin.as_mut().unwrap(), &cert_bytes)
            .await
            .unwrap();
        let out = process.wait_with_output().await.unwrap();
        rendered_cert = Some(String::from_utf8_lossy(&out.stdout).into_owned());
    }

    let mut context = tera::Context::new();
    context.insert("cert", &rendered_cert);
    context.insert("crtsh_url", &crtsh_url);
    let body = templates.render("home.html", &context).unwrap();
    Ok(hyper::Response::builder()
        .status(hyper::StatusCode::OK)
        .body(body.into())
        .unwrap())
}

struct NoVerificationCertificateVerifier;
impl rustls::ClientCertVerifier for NoVerificationCertificateVerifier {
    fn client_auth_mandatory(&self, _: Option<&webpki::DNSName>) -> Option<bool> {
        Some(false)
    }

    fn verify_client_cert(
        &self,
        _: &[rustls::Certificate],
        _: Option<&webpki::DNSName>,
    ) -> Result<rustls::ClientCertVerified, rustls::TLSError> {
        Ok(rustls::ClientCertVerified::assertion())
    }

    fn client_auth_root_subjects(
        &self,
        _: Option<&webpki::DNSName>,
    ) -> Option<rustls::DistinguishedNames> {
        Some(rustls::DistinguishedNames::new())
    }
}

pub fn generate_temporary_cert(
    domain: &str,
) -> (
    openssl::x509::X509,
    openssl::pkey::PKey<openssl::pkey::Private>,
) {
    let pkey = openssl::pkey::PKey::from_rsa(openssl::rsa::Rsa::generate(2048).unwrap()).unwrap();
    let mut cert_builder = openssl::x509::X509Builder::new().unwrap();
    cert_builder.set_version(2).unwrap();
    cert_builder.set_pubkey(&pkey).unwrap();

    let mut serial = openssl::bn::BigNum::new().unwrap();
    serial
        .rand(128, openssl::bn::MsbOption::MAYBE_ZERO, false)
        .unwrap();
    cert_builder
        .set_serial_number(&serial.to_asn1_integer().unwrap())
        .unwrap();

    let mut subject_builder = openssl::x509::X509NameBuilder::new().unwrap();
    subject_builder
        .append_entry_by_text("CN", "ACME SNI Challenge Certificate")
        .unwrap();
    let subject = subject_builder.build();
    cert_builder.set_subject_name(&subject).unwrap();
    cert_builder.set_issuer_name(&subject).unwrap();

    cert_builder
        .set_not_before(&openssl::asn1::Asn1Time::days_from_now(0).unwrap())
        .unwrap();
    cert_builder
        .set_not_after(&openssl::asn1::Asn1Time::days_from_now(1).unwrap())
        .unwrap();

    let mut san = openssl::x509::extension::SubjectAlternativeName::new();
    san.dns(domain);
    let san_ext = san.build(&cert_builder.x509v3_context(None, None)).unwrap();
    cert_builder.append_extension(san_ext).unwrap();

    cert_builder
        .sign(&pkey, openssl::hash::MessageDigest::sha256())
        .unwrap();

    (cert_builder.build(), pkey)
}

pub fn openssl_cert_to_rustls(cert: &openssl::x509::X509) -> rustls::Certificate {
    rustls::Certificate(cert.to_der().unwrap())
}

pub fn openssl_pkey_to_rustls(
    pkey: &openssl::pkey::PKey<openssl::pkey::Private>,
) -> rustls::PrivateKey {
    rustls::PrivateKey(pkey.rsa().unwrap().private_key_to_der().unwrap())
}

async fn server(local_dev: bool, domain: Option<&str>) {
    // Disable certificate verification. In any normal context, this would be horribly insecure!
    // However, all we're doing is taking the certs and then turning around and submitting them to
    // CT logs, so it doesn't matter if they're verified.
    let mut tls_config = rustls::ServerConfig::new(Arc::new(NoVerificationCertificateVerifier));
    if local_dev {
        let (cert, pkey) = generate_temporary_cert(domain.unwrap_or("localhost"));
        tls_config
            .set_single_cert(
                vec![openssl_cert_to_rustls(&cert)],
                openssl_pkey_to_rustls(&pkey),
            )
            .unwrap();
    } else {
        panic!("Real TLS is not quite working at the moment");
    }
    tls_config.set_persistence(rustls::ServerSessionMemoryCache::new(1024));
    tls_config.ticketer = rustls::Ticketer::new();

    let http_client = Arc::new(reqwest::Client::new());
    let logs = Arc::from(fetch_trusted_ct_logs(&http_client).await);
    let templates = Arc::new(tera::Tera::new("templates/*").unwrap());

    let addr = if local_dev {
        "0.0.0.0:8000"
    } else {
        "0.0.0.0:443"
    }
    .parse()
    .unwrap();

    // If there aren't at least two threads, the Let's Encrypt integration will deadlock.
    println!("Listening on https://{} ...", addr);
    let sock_domain = match addr {
        SocketAddr::V4(_) => socket2::Domain::ipv4(),
        SocketAddr::V6(_) => socket2::Domain::ipv6(),
    };
    let socket = socket2::Socket::new(sock_domain, socket2::Type::stream(), None).unwrap();
    socket.set_reuse_port(true).unwrap();
    socket.set_reuse_address(true).unwrap();
    socket.bind(&socket2::SockAddr::from(addr)).unwrap();
    let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(tls_config));
    let listener = tokio::net::TcpListener::from_std(socket.into_tcp_listener()).unwrap();
    let connections = tokio_stream::wrappers::TcpListenerStream::new(listener)
        .and_then(move |sock| tls_acceptor.accept(sock))
        .filter(move |s| futures::future::ready(s.is_ok()))
        .boxed();
    let server = hyper::Server::builder(hyper::server::accept::from_stream(connections)).serve(
        hyper::service::make_service_fn(
            move |conn: &tokio_rustls::server::TlsStream<tokio::net::TcpStream>| {
                let http_client = Arc::clone(&http_client);
                let templates = Arc::clone(&templates);
                let logs = Arc::clone(&logs);
                let client_cert = conn
                    .get_ref()
                    .1
                    .get_peer_certificates()
                    .map(|mut chain| chain.remove(0));

                async {
                    Ok::<_, hyper::Error>(hyper::service::service_fn(
                        move |r: hyper::Request<hyper::Body>| {
                            handle_request(
                                r,
                                Arc::clone(&templates),
                                Arc::clone(&http_client),
                                Arc::clone(&logs),
                                client_cert.clone(),
                            )
                        },
                    ))
                }
            },
        ),
    );

    server.await.unwrap()
}

#[derive(StructOpt)]
#[structopt(name = "ct-tools")]
enum Opt {
    #[structopt(name = "submit", about = "Directly submits certificates to CT logs")]
    Submit {
        #[structopt(
            long = "all-logs",
            help = "Submit to all logs, instead of just ones trusted by Chrome"
        )]
        all_logs: bool,
        #[structopt(help = "Path to certificate or chain")]
        paths: Vec<String>,
    },

    #[structopt(
        name = "check",
        about = "Checks whether a certificate exists in CT logs"
    )]
    Check {
        #[structopt(help = "Path to certificate or chain")]
        paths: Vec<String>,
    },

    #[structopt(
        name = "server",
        about = "Run an HTTPS server that submits client certificates to CT logs"
    )]
    Server {
        #[structopt(
            long = "--local-dev",
            help = "Local development, do not obtain a certificate"
        )]
        local_dev: bool,
        #[structopt(long = "domain", help = "Domain this is running as")]
        domain: Option<String>,
    },
}

#[tokio::main]
async fn main() {
    match Opt::from_args() {
        Opt::Submit { paths, all_logs } => {
            submit(&paths, all_logs).await;
        }
        Opt::Check { paths } => {
            check(&paths).await;
        }
        Opt::Server { local_dev, domain } => {
            server(local_dev, domain.as_ref().map(|s| s.as_ref())).await;
        }
    }
}
<commit_msg>satisfy the clippy gods (#1067)<commit_after>use ct_tools::common::{sha256_hex, Log};
use ct_tools::crtsh;
use ct_tools::ct::submit_cert_to_logs;
use ct_tools::google::{fetch_all_ct_logs, fetch_trusted_ct_logs};
use futures::stream::{StreamExt, TryStreamExt};
use rustls::Session;
use std::fs::{self, File};
use std::io::Read;
use std::net::SocketAddr;
use std::process::Stdio;
use std::sync::Arc;
use std::time::Duration;
use structopt::StructOpt;
use tokio::io::AsyncWriteExt;
use tokio::process::Command;

fn pems_to_chain(data: &[u8]) -> Vec<Vec<u8>> {
    pem::parse_many(data)
        .into_iter()
        .filter(|p| p.tag == "CERTIFICATE")
        .map(|p| p.contents)
        .collect()
}

fn compute_paths(paths: &[String]) -> Vec<String> {
    paths
        .iter()
        .flat_map(|p| {
            if fs::metadata(p).unwrap().is_dir() {
                fs::read_dir(p)
                    .unwrap()
                    .map(|d| d.unwrap().path().to_str().unwrap().to_string())
                    .collect()
            } else {
                vec![p.clone()]
            }
        })
        .collect()
}

async fn submit(paths: &[String], all_logs: bool) {
    let http_client = reqwest::Client::new();

    let logs = if all_logs {
        fetch_all_ct_logs(&http_client).await
    } else {
        fetch_trusted_ct_logs(&http_client).await
    };

    let all_paths = compute_paths(paths);

    let work = futures::stream::iter(all_paths.iter().map(|path| {
        let path = path.to_string();
        let mut contents = Vec::new();
        File::open(&path)
            .unwrap()
            .read_to_end(&mut contents)
            .unwrap();

        let http_client = &http_client;
        let logs = &logs;
        let mut chain = pems_to_chain(&contents);
        async move {
            if chain.len() == 1 {
                // TODO: There's got to be some way to do this ourselves, instead of using crt.sh
                // as a glorified AIA chaser.
                println!(
                    "[{}] Only one certificate in chain, using crt.sh to build a full chain ...",
                    &path
                );
                let new_chain = crtsh::build_chain_for_cert(http_client, &chain[0]).await;
                chain = match new_chain {
                    Ok(c) => c,
                    Err(()) => {
                        println!("[{}] Unable to build a chain", path);
                        return;
                    }
                }
            }
            println!("[{}] Submitting ...", &path);
            let timeout = Duration::from_secs(30);
            let scts = submit_cert_to_logs(http_client, logs, &chain, timeout).await;

            if !scts.is_empty() {
                println!(
                    "[{}] Find the cert on crt.sh: {}",
                    path,
                    crtsh::url_for_cert(&chain[0])
                );
                let mut table = prettytable::Table::new();
                table.add_row(prettytable::Row::new(vec![prettytable::Cell::new("Log")]));
                for (log_idx, _) in scts {
                    let log = &logs[log_idx];
                    table.add_row(prettytable::Row::new(vec![prettytable::Cell::new(
                        &log.description,
                    )]));
                }
                table.printstd();
                println!();
                println!();
            } else {
                println!("[{}] No SCTs obtained", &path);
            }
        }
    }))
    .buffer_unordered(4)
    .for_each(|_| async {});
    work.await;
}

async fn check(paths: &[String]) {
    let http_client = reqwest::Client::new();

    let all_paths = compute_paths(paths);

    let work = futures::stream::iter(all_paths.iter().map(|path| {
        let path = path.to_string();
        let mut contents = Vec::new();
        File::open(&path)
            .unwrap()
            .read_to_end(&mut contents)
            .unwrap();

        let http_client = &http_client;
        let chain = pems_to_chain(&contents);
        async move {
            if !chain.is_empty() && crtsh::is_cert_logged(http_client, &chain[0]).await {
                println!("{} was already logged", path);
            } else {
                println!("{} has not been logged", path);
            }
        }
    }))
    .buffer_unordered(16)
    .for_each(|_| async {});
    work.await;
}

async fn handle_request(
    request: hyper::Request<hyper::Body>,
    templates: Arc<tera::Tera>,
    http_client: Arc<reqwest::Client>,
    logs: Arc<[Log]>,
    client_cert: Option<rustls::Certificate>,
) -> Result<hyper::Response<hyper::Body>, hyper::Error> {
    let mut crtsh_url = None;
    let mut rendered_cert = None;
    if let Some(cert) = client_cert {
        if request.method() == hyper::Method::POST {
            if let Ok(chain) = crtsh::build_chain_for_cert(&http_client, &cert.0).await {
                let timeout = Duration::from_secs(5);
                let scts = submit_cert_to_logs(&http_client, &logs, &chain, timeout).await;
                if !scts.is_empty() {
                    crtsh_url = Some(crtsh::url_for_cert(&chain[0]));
                    println!("Successfully submitted: {}", sha256_hex(&chain[0]));
                }
            }
        }

        let mut process = Command::new("openssl")
            .arg("x509")
            .arg("-text")
            .arg("-noout")
            .arg("-inform")
            .arg("der")
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .unwrap();
        let cert_bytes = cert.0.clone();
        AsyncWriteExt::write_all(&mut process.stdin.as_mut().unwrap(), &cert_bytes)
            .await
            .unwrap();
        let out = process.wait_with_output().await.unwrap();
        rendered_cert = Some(String::from_utf8_lossy(&out.stdout).into_owned());
    }

    let mut context = tera::Context::new();
    context.insert("cert", &rendered_cert);
    context.insert("crtsh_url", &crtsh_url);
    let body = templates.render("home.html", &context).unwrap();
    Ok(hyper::Response::builder()
        .status(hyper::StatusCode::OK)
        .body(body.into())
        .unwrap())
}

struct NoVerificationCertificateVerifier;
impl rustls::ClientCertVerifier for NoVerificationCertificateVerifier {
    fn client_auth_mandatory(&self, _: Option<&webpki::DNSName>) -> Option<bool> {
        Some(false)
    }

    fn verify_client_cert(
        &self,
        _: &[rustls::Certificate],
        _: Option<&webpki::DNSName>,
    ) -> Result<rustls::ClientCertVerified, rustls::TLSError> {
        Ok(rustls::ClientCertVerified::assertion())
    }

    fn client_auth_root_subjects(
        &self,
        _: Option<&webpki::DNSName>,
    ) -> Option<rustls::DistinguishedNames> {
        Some(rustls::DistinguishedNames::new())
    }
}

pub fn generate_temporary_cert(
    domain: &str,
) -> (
    openssl::x509::X509,
    openssl::pkey::PKey<openssl::pkey::Private>,
) {
    let pkey = openssl::pkey::PKey::from_rsa(openssl::rsa::Rsa::generate(2048).unwrap()).unwrap();
    let mut cert_builder = openssl::x509::X509Builder::new().unwrap();
    cert_builder.set_version(2).unwrap();
    cert_builder.set_pubkey(&pkey).unwrap();

    let mut serial = openssl::bn::BigNum::new().unwrap();
    serial
        .rand(128, openssl::bn::MsbOption::MAYBE_ZERO, false)
        .unwrap();
    cert_builder
        .set_serial_number(&serial.to_asn1_integer().unwrap())
        .unwrap();

    let mut subject_builder = openssl::x509::X509NameBuilder::new().unwrap();
    subject_builder
        .append_entry_by_text("CN", "ACME SNI Challenge Certificate")
        .unwrap();
    let subject = subject_builder.build();
    cert_builder.set_subject_name(&subject).unwrap();
    cert_builder.set_issuer_name(&subject).unwrap();

    cert_builder
        .set_not_before(&openssl::asn1::Asn1Time::days_from_now(0).unwrap())
        .unwrap();
    cert_builder
        .set_not_after(&openssl::asn1::Asn1Time::days_from_now(1).unwrap())
        .unwrap();

    let mut san = openssl::x509::extension::SubjectAlternativeName::new();
    san.dns(domain);
    let san_ext = san.build(&cert_builder.x509v3_context(None, None)).unwrap();
    cert_builder.append_extension(san_ext).unwrap();

    cert_builder
        .sign(&pkey, openssl::hash::MessageDigest::sha256())
        .unwrap();

    (cert_builder.build(), pkey)
}

pub fn openssl_cert_to_rustls(cert: &openssl::x509::X509) -> rustls::Certificate {
    rustls::Certificate(cert.to_der().unwrap())
}

pub fn openssl_pkey_to_rustls(
    pkey: &openssl::pkey::PKey<openssl::pkey::Private>,
) -> rustls::PrivateKey {
    rustls::PrivateKey(pkey.rsa().unwrap().private_key_to_der().unwrap())
}

async fn server(local_dev: bool, domain: Option<&str>) {
    // Disable certificate verification. In any normal context, this would be horribly insecure!
    // However, all we're doing is taking the certs and then turning around and submitting them to
    // CT logs, so it doesn't matter if they're verified.
    let mut tls_config = rustls::ServerConfig::new(Arc::new(NoVerificationCertificateVerifier));
    if local_dev {
        let (cert, pkey) = generate_temporary_cert(domain.unwrap_or("localhost"));
        tls_config
            .set_single_cert(
                vec![openssl_cert_to_rustls(&cert)],
                openssl_pkey_to_rustls(&pkey),
            )
            .unwrap();
    } else {
        panic!("Real TLS is not quite working at the moment");
    }
    tls_config.set_persistence(rustls::ServerSessionMemoryCache::new(1024));
    tls_config.ticketer = rustls::Ticketer::new();

    let http_client = Arc::new(reqwest::Client::new());
    let logs = Arc::from(fetch_trusted_ct_logs(&http_client).await);
    let templates = Arc::new(tera::Tera::new("templates/*").unwrap());

    let addr = if local_dev {
        "0.0.0.0:8000"
    } else {
        "0.0.0.0:443"
    }
    .parse()
    .unwrap();

    // If there aren't at least two threads, the Let's Encrypt integration will deadlock.
    println!("Listening on https://{} ...", addr);
    let sock_domain = match addr {
        SocketAddr::V4(_) => socket2::Domain::ipv4(),
        SocketAddr::V6(_) => socket2::Domain::ipv6(),
    };
    let socket = socket2::Socket::new(sock_domain, socket2::Type::stream(), None).unwrap();
    socket.set_reuse_port(true).unwrap();
    socket.set_reuse_address(true).unwrap();
    socket.bind(&socket2::SockAddr::from(addr)).unwrap();
    let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(tls_config));
    let listener = tokio::net::TcpListener::from_std(socket.into_tcp_listener()).unwrap();
    let connections = tokio_stream::wrappers::TcpListenerStream::new(listener)
        .and_then(move |sock| tls_acceptor.accept(sock))
        .filter(move |s| futures::future::ready(s.is_ok()))
        .boxed();
    let server = hyper::Server::builder(hyper::server::accept::from_stream(connections)).serve(
        hyper::service::make_service_fn(
            move |conn: &tokio_rustls::server::TlsStream<tokio::net::TcpStream>| {
                let http_client = Arc::clone(&http_client);
                let templates = Arc::clone(&templates);
                let logs = Arc::clone(&logs);
                let client_cert = conn
                    .get_ref()
                    .1
                    .get_peer_certificates()
                    .map(|mut chain| chain.remove(0));

                async {
                    Ok::<_, hyper::Error>(hyper::service::service_fn(
                        move |r: hyper::Request<hyper::Body>| {
                            handle_request(
                                r,
                                Arc::clone(&templates),
                                Arc::clone(&http_client),
                                Arc::clone(&logs),
                                client_cert.clone(),
                            )
                        },
                    ))
                }
            },
        ),
    );

    server.await.unwrap()
}

#[derive(StructOpt)]
#[structopt(name = "ct-tools")]
enum Opt {
    #[structopt(name = "submit", about = "Directly submits certificates to CT logs")]
    Submit {
        #[structopt(
            long = "all-logs",
            help = "Submit to all logs, instead of just ones trusted by Chrome"
        )]
        all_logs: bool,
        #[structopt(help = "Path to certificate or chain")]
        paths: Vec<String>,
    },

    #[structopt(
        name = "check",
        about = "Checks whether a certificate exists in CT logs"
    )]
    Check {
        #[structopt(help = "Path to certificate or chain")]
        paths: Vec<String>,
    },

    #[structopt(
        name = "server",
        about = "Run an HTTPS server that submits client certificates to CT logs"
    )]
    Server {
        #[structopt(
            long = "--local-dev",
            help = "Local development, do not obtain a certificate"
        )]
        local_dev: bool,
        #[structopt(long = "domain", help = "Domain this is running as")]
        domain: Option<String>,
    },
}

#[tokio::main]
async fn main() {
    match Opt::from_args() {
        Opt::Submit { paths, all_logs } => {
            submit(&paths, all_logs).await;
        }
        Opt::Check { paths } => {
            check(&paths).await;
        }
        Opt::Server { local_dev, domain } => {
            server(local_dev, domain.as_ref().map(|s| s.as_ref())).await;
        }
    }
}
<|endoftext|>


<commit_before>#![feature(path_ext)]
extern crate mysql;
extern crate ini;
#[macro_use]
extern crate lazy_static;

use mysql::conn::MyOpts;
use std::default::Default;
use mysql::conn::pool;
use mysql::value::from_value;

use ini::Ini;

use std::env::current_dir;
use std::path::PathBuf;
use std::path::Path;
use std::fs::PathExt;

use std::collections::HashMap;

static VERSION : &'static str = "0.1"; // String not valid

lazy_static! {
	static ref CONFIG: HashMap< &'static str, String> = {
		let mut m = HashMap::new();
		m.insert("user", "root".to_string());
		m.insert("password", "".to_string());
		m.insert("db", "testdb".to_string());
		m.insert("ip", "127.0.0.1".to_string());
		m //return
	};

}

fn main() {
    println!("Starting yayd-backend v{}",&VERSION);

    init_config();

    let options = mysql_options();
    let pool = pool::MyPool::new(options).unwrap();

}

/// create PathBuf by getting the current working dir
/// set_file_name doesn't return smth -> needs to be run on mut path
fn init_config(){
    let mut path = current_dir().unwrap();
    path.set_file_name("config.cfg");
    // let  = path.as_path();
    println!("{:?}",path );
    if(path.as_path().is_file()) {
    	println!("Config file found.");
    }else{
    	println!("Config file not found.");
    	create_config(path.to_str().unwrap());
    }
}

fn create_config(file: &str){
	let mut conf = Ini::new();
	conf.begin_section("DB")
		.set("user","root")
		.set("password", "")
		.set("db","testdb")
		.set("ip", "127.0.0.1");
	conf.write_to_file(file);
}

/// Set options for the connection
fn mysql_options() -> MyOpts {
    MyOpts {
    	tcp_addr: Some(CONFIG.get("ip").unwrap().clone()),
    	tcp_port: 3306,
    	//tcp_port: "3306"
    	user: Some(CONFIG.get("user").unwrap().clone()),
    	pass: Some(CONFIG.get("password").unwrap().clone()),
    	db_name: Some(CONFIG.get("db").unwrap().clone()),
    	..Default::default() // set other to default
    }
}<commit_msg>+ini file creation *exception handling<commit_after>#![feature(path_ext)]
extern crate mysql;
extern crate ini;
#[macro_use]
extern crate lazy_static;

use mysql::conn::MyOpts;
use std::default::Default;
use mysql::conn::pool;
use mysql::value::from_value;

use ini::Ini;

use std::env::current_dir;
use std::path::PathBuf;
use std::path::Path;
use std::fs::PathExt;
use std::fs::File;

use std::collections::HashMap;

static VERSION : &'static str = "0.1"; // String not valid

lazy_static! {
	static ref CONFIG: HashMap< &'static str, String> = {
		let mut m = HashMap::new();
		m.insert("user", "root".to_string());
		m.insert("password", "".to_string());
		m.insert("db", "testdb".to_string());
		m.insert("ip", "127.0.0.1".to_string());
		m //return
	};

}

fn main() {
    println!("Starting yayd-backend v{}",&VERSION);

    init_config();

    let options = mysql_options();
    let pool = pool::MyPool::new(options).unwrap();

}

/// create PathBuf by getting the current working dir
/// set_file_name doesn't return smth -> needs to be run on mut path
fn init_config(){
    let mut path = current_dir().unwrap();
    path.set_file_name("config.cfg");
    // let  = path.as_path();
    println!("{:?}",path );
    if(path.as_path().is_file()) {
    	println!("Config file found.");
    }else{
    	println!("Config file not found.");
    	let mut file = File::create(path.to_str().unwrap()).unwrap();
    	create_config(&mut file);
    }
}

fn create_config(file: &mut File){
	let mut conf = Ini::new();
	conf.begin_section("DB")
		.set("user","root")
		.set("password", "")
		.set("db","testdb")
		.set("ip", "127.0.0.1");
	// println!("{:?}", file.display());
	let result = conf.write_to(file);
	match result {
		Ok(_) => {},
		Err(err) => panic!("Error writing the config: {}",err),
	};
}

/// Set options for the connection
fn mysql_options() -> MyOpts {
    MyOpts {
    	tcp_addr: Some(CONFIG.get("ip").unwrap().clone()),
    	tcp_port: 3306,
    	//tcp_port: "3306"
    	user: Some(CONFIG.get("user").unwrap().clone()),
    	pass: Some(CONFIG.get("password").unwrap().clone()),
    	db_name: Some(CONFIG.get("db").unwrap().clone()),
    	..Default::default() // set other to default
    }
}<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate entities;

use std::char;
use docopt::Docopt;
use entities::ENTITIES;

const USAGE: &'static str = "
how-do-i-escape: Prints escape sequences for unicode graphemes

Usage:
  how-do-i-escape <grapheme>
  how-do-i-escape (--help | --version)

Options:
  -h, --help  Show this screen.
  --version   Show version.

Example:
  $ how-do-i-escape \u{00A7}
  css  = \"\\00A7\"
  html = §
  js   = \"\\u00A7\"
";

#[derive(RustcDecodable)]
struct Args {
    arg_grapheme: String,
}

fn main() {
    let version = format!("v{}", env!("CARGO_PKG_VERSION"));

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.help(true).version(Some(version)).decode())
        .unwrap_or_else(|e| e.exit());

    let grapheme = args.arg_grapheme;

    println!(r#"css  = "{}""#, escape_grapheme(&grapheme, as_css));
    println!(r#"html = {}"#, escape_grapheme(&grapheme, as_html));
    println!(r#"js   = "{}""#, escape_grapheme(&grapheme, as_js));
}

fn escape_grapheme<F>(grapheme: &str, int_to_escape_sequence: F) -> String
    where F: Fn(u32) -> String
{
    grapheme.chars()
        .map(|ch| ch as u32)
        .map(int_to_escape_sequence)
        .collect()
}

fn as_css(i: u32) -> String {
    format!("\\{:01$X}", i, 4)
}

fn as_js(i: u32) -> String {
    if i <= 0xFFFF {
        format!("\\u{:01$X}", i, 4)
    } else {
        format!("\\u{{{:X}}}", i)
    }
}

fn as_html(i: u32) -> String {
    // Some characters have multiple entity options
    // e.g. " and "
    let entity_options = ENTITIES.iter().filter(|e| {
        match e.codepoints {
            entities::Codepoints::Single(cp) => cp == i,
            _ => false,
        }
    }).collect::<Vec<_>>();

    if entity_options.is_empty() {
        format!("&#x{:01$X};", i, 4)
    } else {
        let nicest = choose_nice_entity(entity_options);
        nicest.entity.to_string()
    }
}

// "nice" means prefer lowercase and ends with a semicolon
fn choose_nice_entity(options: Vec<&entities::Entity>) -> &entities::Entity {
    assert!(!options.is_empty());

    let nicest_entity = options.iter().find(|entity| {
        has_semicolon(entity) && !is_all_caps(entity)
    });

    if let Some(entity) = nicest_entity {
        return entity;
    }

    let less_nice_entity = options.iter().find(|entity| {
        has_semicolon(entity)
    });

    if let Some(entity) = less_nice_entity {
        return entity;
    }

    let ok_entity = options.iter().find(|entity| {
        !is_all_caps(entity)
    });

    if let Some(entity) = ok_entity {
        return entity;
    }

    options[0]
}

fn has_semicolon(entity: &entities::Entity) -> bool {
    entity.entity.ends_with(";")
}

fn is_all_caps(entity: &entities::Entity) -> bool {
    !entity.entity.chars().any(char::is_lowercase)
}

#[cfg(test)]
mod tests {
    use super::{as_css, as_html, as_js, escape_grapheme};

    #[test]
    fn test_as_css() {
        assert!(as_css(0) == r"\0000");
        assert!(as_css(0xFFFF) == r"\FFFF");
        assert!(as_css(0xBEEF) != r"\beef");
        // assert!(as_css(0x10000) == ?);
    }

    #[test]
    fn test_as_html() {
        assert!(as_html(0) == r"�");
        assert!(as_html(0xFFFF) == r"");
        assert!(as_html(0xBEEF) != r"뻯");
        assert!(as_html(',' as u32) == r",");
        assert!(as_html('>' as u32) == r">");
        // assert!(as_html(0x10000) == ?);
    }

    #[test]
    fn test_as_js() {
        assert!(as_js(0) == r"\u0000");
        assert!(as_js(0xFFFF) == r"\uFFFF");
        assert!(as_js(0xBEEF) != r"\ubeef");
        assert!(as_js(0x10000) == r"\u{10000}");
        assert!(as_js(0x10FFFF) == r"\u{10FFFF}");
        assert!(as_js(0xFFFFFFFF) == r"\u{FFFFFFFF}");
    }

    #[test]
    fn test_escape_grapheme() {
        let always_hello = escape_grapheme("\u{FF}", |_| "hello".to_string());
        assert!(always_hello == "hello");

        let simple = escape_grapheme("\u{FF}", |i| format!("{}", i));
        assert!(simple == "255");
    }
}
<commit_msg>Swith to the easier to debug assert_eq macro for tests<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate entities;

use std::char;
use docopt::Docopt;
use entities::ENTITIES;

const USAGE: &'static str = "
how-do-i-escape: Prints escape sequences for unicode graphemes

Usage:
  how-do-i-escape <grapheme>
  how-do-i-escape (--help | --version)

Options:
  -h, --help  Show this screen.
  --version   Show version.

Example:
  $ how-do-i-escape \u{00A7}
  css  = \"\\00A7\"
  html = §
  js   = \"\\u00A7\"
";

#[derive(RustcDecodable)]
struct Args {
    arg_grapheme: String,
}

fn main() {
    let version = format!("v{}", env!("CARGO_PKG_VERSION"));

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.help(true).version(Some(version)).decode())
        .unwrap_or_else(|e| e.exit());

    let grapheme = args.arg_grapheme;

    println!(r#"css  = "{}""#, escape_grapheme(&grapheme, as_css));
    println!(r#"html = {}"#, escape_grapheme(&grapheme, as_html));
    println!(r#"js   = "{}""#, escape_grapheme(&grapheme, as_js));
}

fn escape_grapheme<F>(grapheme: &str, int_to_escape_sequence: F) -> String
    where F: Fn(u32) -> String
{
    grapheme.chars()
        .map(|ch| ch as u32)
        .map(int_to_escape_sequence)
        .collect()
}

fn as_css(i: u32) -> String {
    format!("\\{:01$X}", i, 4)
}

fn as_js(i: u32) -> String {
    if i <= 0xFFFF {
        format!("\\u{:01$X}", i, 4)
    } else {
        format!("\\u{{{:X}}}", i)
    }
}

fn as_html(i: u32) -> String {
    // Some characters have multiple entity options
    // e.g. " and "
    let entity_options = ENTITIES.iter().filter(|e| {
        match e.codepoints {
            entities::Codepoints::Single(cp) => cp == i,
            _ => false,
        }
    }).collect::<Vec<_>>();

    if entity_options.is_empty() {
        format!("&#x{:01$X};", i, 4)
    } else {
        let nicest = choose_nice_entity(entity_options);
        nicest.entity.to_string()
    }
}

// "nice" means prefer lowercase and ends with a semicolon
fn choose_nice_entity(options: Vec<&entities::Entity>) -> &entities::Entity {
    assert!(!options.is_empty());

    let nicest_entity = options.iter().find(|entity| {
        has_semicolon(entity) && !is_all_caps(entity)
    });

    if let Some(entity) = nicest_entity {
        return entity;
    }

    let less_nice_entity = options.iter().find(|entity| {
        has_semicolon(entity)
    });

    if let Some(entity) = less_nice_entity {
        return entity;
    }

    let ok_entity = options.iter().find(|entity| {
        !is_all_caps(entity)
    });

    if let Some(entity) = ok_entity {
        return entity;
    }

    options[0]
}

fn has_semicolon(entity: &entities::Entity) -> bool {
    entity.entity.ends_with(";")
}

fn is_all_caps(entity: &entities::Entity) -> bool {
    !entity.entity.chars().any(char::is_lowercase)
}

#[cfg(test)]
mod tests {
    use super::{as_css, as_html, as_js, escape_grapheme};

    #[test]
    fn test_as_css() {
        assert_eq!(as_css(0), r"\0000");
        assert_eq!(as_css(0xFFFF), r"\FFFF");
        assert_ne!(as_css(0xBEEF), r"\beef");
        // assert_eq!(as_css(0x10000), ?);
    }

    #[test]
    fn test_as_html() {
        assert_eq!(as_html(0), r"�");
        assert_eq!(as_html(0xFFFF), r"");
        assert_ne!(as_html(0xBEEF), r"뻯");
        assert_eq!(as_html(',' as u32), r",");
        assert_eq!(as_html('>' as u32), r">");
        // assert_eq!(as_html(0x10000), ?);
    }

    #[test]
    fn test_as_js() {
        assert_eq!(as_js(0), r"\u0000");
        assert_eq!(as_js(0xFFFF), r"\uFFFF");
        assert_ne!(as_js(0xBEEF), r"\ubeef");
        assert_eq!(as_js(0x10000), r"\u{10000}");
        assert_eq!(as_js(0x10FFFF), r"\u{10FFFF}");
        assert_eq!(as_js(0xFFFFFFFF), r"\u{FFFFFFFF}");
    }

    #[test]
    fn test_escape_grapheme() {
        let always_hello = escape_grapheme("\u{FF}", |_| "hello".to_string());
        assert_eq!(always_hello, "hello");

        let simple = escape_grapheme("\u{FF}", |i| format!("{}", i));
        assert_eq!(simple, "255");
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate static_file;
extern crate mount;

use std::io::net::ip::Ipv4Addr;
use iron::Iron;
use static_file::Static;
use mount::Mount;

fn main() {
    let mut mount = Mount::new();

    mount.mount("/", Static::new(Path::new("webui/")));

    Iron::new(mount).listen(Ipv4Addr(127, 0, 0, 1), 3000);
    println!("Listening on http://localhost:3000");
}
<commit_msg>Stub out login endpoint<commit_after>extern crate iron;
extern crate static_file;
extern crate mount;

use std::io::net::ip::Ipv4Addr;
use iron::{Iron, Request, Response, IronResult};
use iron::status;
use static_file::Static;
use mount::Mount;

fn login(_req: &mut Request) -> IronResult<Response> {
    Ok(Response::with(status::Ok, "Seems good bro"))
}

fn main() {
    let mut mount = Mount::new();

    mount.mount("/login", login);
    mount.mount("/", Static::new(Path::new("webui/")));

    Iron::new(mount).listen(Ipv4Addr(127, 0, 0, 1), 3000);
    println!("Listening on http://localhost:3000");
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// 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.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(range_contains)]
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![feature(unicode)]
#![feature(step_trait)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
#![feature(core_intrinsics)]

extern crate cgmath;
extern crate errno;
extern crate font;
extern crate glutin;
extern crate libc;
extern crate notify;
extern crate parking_lot;
extern crate serde;
extern crate serde_yaml;
extern crate vte;

#[macro_use]
extern crate bitflags;

#[macro_use]
mod macros;

mod renderer;
pub mod grid;
mod meter;
pub mod config;
mod input;
mod index;
mod event;
mod tty;
pub mod ansi;
mod term;
mod util;
mod sync;

use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering};

use parking_lot::{Condvar, Mutex, MutexGuard};

use config::Config;
use meter::Meter;
use renderer::{QuadRenderer, GlyphCache};
use sync::PriorityMutex;
use term::Term;
use tty::process_should_exit;
use util::thread;

/// Channel used by resize handling on mac
static mut resize_sender: Option<mpsc::Sender<(u32, u32)>> = None;

#[derive(Clone)]
struct Flag(Arc<AtomicBool>);
impl Flag {
    pub fn new(initial_value: bool) -> Flag {
        Flag(Arc::new(AtomicBool::new(initial_value)))
    }

    #[inline]
    pub fn get(&self) -> bool {
        self.0.load(Ordering::Acquire)
    }

    #[inline]
    pub fn set(&self, value: bool) {
        self.0.store(value, Ordering::Release)
    }
}

/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        if let Some(ref tx) = resize_sender {
            let _ = tx.send((width, height));
        }
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

fn main() {
    // Load configuration
    let config = match Config::load() {
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => Config::default(),
            // Exit when there's a problem with it
            _ => die!("{}", err),
        },
        Ok(config) => config,
    };

    let font = config.font();
    let dpi = config.dpi();
    let render_timer = config.render_timer();

    let mut window = glutin::WindowBuilder::new()
                                           .with_vsync()
                                           .with_title("Alacritty")
                                           .build().unwrap();

    window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    let (width, height) = window.get_inner_size_pixels().unwrap();
    let dpr = window.hidpi_factor();

    println!("device_pixel_ratio: {}", dpr);

    let _ = unsafe { window.make_current() };
    unsafe {
        gl::Viewport(0, 0, width as i32, height as i32);
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);

    // Create renderer
    let mut renderer = QuadRenderer::new(width, height);

    // Initialize glyph cache
    let glyph_cache = {
        println!("Initializing glyph cache");
        let init_start = ::std::time::Instant::now();

        let cache = renderer.with_loader(|mut api| {
            GlyphCache::new(rasterizer, &config, &mut api)
        });

        let stop = init_start.elapsed();
        let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
        println!("Finished initializing glyph cache in {}", stop_f);

        cache
    };

    let metrics = glyph_cache.font_metrics();
    let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
    let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;

    println!("Cell Size: ({} x {})", cell_width, cell_height);

    let terminal = Term::new(width as f32, height as f32, cell_width as f32, cell_height as f32);

    let reader = terminal.tty().reader();
    let mut writer = terminal.tty().writer();

    let (tx, rx) = mpsc::channel();
    unsafe {
        resize_sender = Some(tx.clone());
    }

    let signal_flag = Flag::new(false);

    let terminal = Arc::new(PriorityMutex::new(terminal));
    let window = Arc::new(window);

    let pty_reader = PtyReader::spawn(
        terminal.clone(),
        reader,
        window.create_window_proxy(),
        signal_flag.clone()
    );

    // Wraps a renderer and gives simple draw() api.
    let mut display = Display::new(
        window.clone(),
        terminal.clone(),
        renderer,
        glyph_cache,
        render_timer,
        rx
    );

    // Event processor
    let mut processor = event::Processor::new(&mut writer, terminal.clone(), tx);

    // Main loop
    loop {
        // Wait for something to happen
        processor.process_events(&window);

        signal_flag.set(false);

        // Maybe draw the terminal
        let terminal = terminal.lock_high();
        if terminal.dirty {
            display.draw(terminal);
        }

        if process_should_exit() {
            break;
        }
    }

    // shutdown
    pty_reader.join().ok();
    println!("Goodbye");
}

struct PtyReader;

impl PtyReader {
    pub fn spawn<R>(terminal: Arc<PriorityMutex<Term>>,
                    mut pty: R,
                    proxy: ::glutin::WindowProxy,
                    signal_flag: Flag)
                    -> std::thread::JoinHandle<()>
        where R: std::io::Read + Send + 'static
    {
        thread::spawn_named("pty reader", move || {
            let mut buf = [0u8; 4096];
            let mut pty_parser = ansi::Processor::new();

            loop {
                if let Ok(got) = pty.read(&mut buf[..]) {
                    let mut terminal = terminal.lock_high();

                    for byte in &buf[..got] {
                        pty_parser.advance(&mut *terminal, *byte);
                    }

                    terminal.dirty = true;

                    // Only wake up the event loop if it hasn't already been signaled. This is a
                    // really important optimization because waking up the event loop redundantly
                    // burns *a lot* of cycles.
                    if !signal_flag.get() {
                        proxy.wakeup_event_loop();
                        signal_flag.set(true);
                    }
                } else {
                    break;
                }
            }

            println!("pty reader stopped");
        })
    }
}

struct Display {
    window: Arc<glutin::Window>,
    terminal_mutex: Arc<PriorityMutex<Term>>,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    meter: Meter,
}

impl Display {
    pub fn new(window: Arc<glutin::Window>,
               terminal_mutex: Arc<PriorityMutex<Term>>,
               renderer: QuadRenderer,
               glyph_cache: GlyphCache,
               render_timer: bool,
               rx: mpsc::Receiver<(u32, u32)>)
               -> Display
    {
        Display {
            window: window,
            terminal_mutex: terminal_mutex,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            rx: rx,
            meter: Meter::new(),
        }
    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>) {
        terminal.dirty = false;

        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // TODO should be built into renderer
        unsafe {
            gl::ClearColor(0.0, 0.0, 0.00, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }

        // Check for any out-of-band resize events (mac only)
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            terminal.resize(w as f32, h as f32);
            self.renderer.resize(w as i32, h as i32);
        }

        {
            let glyph_cache = &mut self.glyph_cache;
            // Draw grid
            {
                let _sampler = self.meter.sampler();

                let size_info = terminal.size_info().clone();
                self.renderer.with_api(&size_info, |mut api| {
                    // Draw the grid
                    api.render_grid(&terminal.render_grid(), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                self.renderer.with_api(terminal.size_info(), |mut api| {
                    api.render_string(&timing[..], glyph_cache, &color);
                });
            }
        }

        // Unlock the terminal mutex
        drop(terminal);
        self.window.swap_buffers().unwrap();
    }
}
<commit_msg>Fix refresh bug<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// 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.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(range_contains)]
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![feature(unicode)]
#![feature(step_trait)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
#![feature(core_intrinsics)]

extern crate cgmath;
extern crate errno;
extern crate font;
extern crate glutin;
extern crate libc;
extern crate notify;
extern crate parking_lot;
extern crate serde;
extern crate serde_yaml;
extern crate vte;

#[macro_use]
extern crate bitflags;

#[macro_use]
mod macros;

mod renderer;
pub mod grid;
mod meter;
pub mod config;
mod input;
mod index;
mod event;
mod tty;
pub mod ansi;
mod term;
mod util;
mod sync;

use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering};

use parking_lot::{Condvar, Mutex, MutexGuard};

use config::Config;
use meter::Meter;
use renderer::{QuadRenderer, GlyphCache};
use sync::PriorityMutex;
use term::Term;
use tty::process_should_exit;
use util::thread;

/// Channel used by resize handling on mac
static mut resize_sender: Option<mpsc::Sender<(u32, u32)>> = None;

#[derive(Clone)]
struct Flag(Arc<AtomicBool>);
impl Flag {
    pub fn new(initial_value: bool) -> Flag {
        Flag(Arc::new(AtomicBool::new(initial_value)))
    }

    #[inline]
    pub fn get(&self) -> bool {
        self.0.load(Ordering::Acquire)
    }

    #[inline]
    pub fn set(&self, value: bool) {
        self.0.store(value, Ordering::Release)
    }
}

/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        if let Some(ref tx) = resize_sender {
            let _ = tx.send((width, height));
        }
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

fn main() {
    // Load configuration
    let config = match Config::load() {
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => Config::default(),
            // Exit when there's a problem with it
            _ => die!("{}", err),
        },
        Ok(config) => config,
    };

    let font = config.font();
    let dpi = config.dpi();
    let render_timer = config.render_timer();

    let mut window = glutin::WindowBuilder::new()
                                           .with_vsync()
                                           .with_title("Alacritty")
                                           .build().unwrap();

    window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    let (width, height) = window.get_inner_size_pixels().unwrap();
    let dpr = window.hidpi_factor();

    println!("device_pixel_ratio: {}", dpr);

    let _ = unsafe { window.make_current() };
    unsafe {
        gl::Viewport(0, 0, width as i32, height as i32);
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);

    // Create renderer
    let mut renderer = QuadRenderer::new(width, height);

    // Initialize glyph cache
    let glyph_cache = {
        println!("Initializing glyph cache");
        let init_start = ::std::time::Instant::now();

        let cache = renderer.with_loader(|mut api| {
            GlyphCache::new(rasterizer, &config, &mut api)
        });

        let stop = init_start.elapsed();
        let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
        println!("Finished initializing glyph cache in {}", stop_f);

        cache
    };

    let metrics = glyph_cache.font_metrics();
    let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
    let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;

    println!("Cell Size: ({} x {})", cell_width, cell_height);

    let terminal = Term::new(width as f32, height as f32, cell_width as f32, cell_height as f32);

    let reader = terminal.tty().reader();
    let mut writer = terminal.tty().writer();

    let (tx, rx) = mpsc::channel();
    unsafe {
        resize_sender = Some(tx.clone());
    }

    let signal_flag = Flag::new(false);

    let terminal = Arc::new(PriorityMutex::new(terminal));
    let window = Arc::new(window);

    let pty_reader = PtyReader::spawn(
        terminal.clone(),
        reader,
        window.create_window_proxy(),
        signal_flag.clone()
    );

    // Wraps a renderer and gives simple draw() api.
    let mut display = Display::new(
        window.clone(),
        terminal.clone(),
        renderer,
        glyph_cache,
        render_timer,
        rx
    );

    // Event processor
    let mut processor = event::Processor::new(&mut writer, terminal.clone(), tx);

    // Main loop
    loop {
        // Wait for something to happen
        processor.process_events(&window);

        // Maybe draw the terminal
        let terminal = terminal.lock_high();
        signal_flag.set(false);
        if terminal.dirty {
            display.draw(terminal);
        }

        if process_should_exit() {
            break;
        }
    }

    // shutdown
    pty_reader.join().ok();
    println!("Goodbye");
}

struct PtyReader;

impl PtyReader {
    pub fn spawn<R>(terminal: Arc<PriorityMutex<Term>>,
                    mut pty: R,
                    proxy: ::glutin::WindowProxy,
                    signal_flag: Flag)
                    -> std::thread::JoinHandle<()>
        where R: std::io::Read + Send + 'static
    {
        thread::spawn_named("pty reader", move || {
            let mut buf = [0u8; 4096];
            let mut pty_parser = ansi::Processor::new();

            loop {
                if let Ok(got) = pty.read(&mut buf[..]) {
                    let mut terminal = terminal.lock_high();

                    for byte in &buf[..got] {
                        pty_parser.advance(&mut *terminal, *byte);
                    }

                    terminal.dirty = true;

                    // Only wake up the event loop if it hasn't already been signaled. This is a
                    // really important optimization because waking up the event loop redundantly
                    // burns *a lot* of cycles.
                    if !signal_flag.get() {
                        proxy.wakeup_event_loop();
                        signal_flag.set(true);
                    }
                } else {
                    break;
                }
            }

            println!("pty reader stopped");
        })
    }
}

struct Display {
    window: Arc<glutin::Window>,
    terminal_mutex: Arc<PriorityMutex<Term>>,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    meter: Meter,
}

impl Display {
    pub fn new(window: Arc<glutin::Window>,
               terminal_mutex: Arc<PriorityMutex<Term>>,
               renderer: QuadRenderer,
               glyph_cache: GlyphCache,
               render_timer: bool,
               rx: mpsc::Receiver<(u32, u32)>)
               -> Display
    {
        Display {
            window: window,
            terminal_mutex: terminal_mutex,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            rx: rx,
            meter: Meter::new(),
        }
    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>) {
        terminal.dirty = false;

        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // TODO should be built into renderer
        unsafe {
            gl::ClearColor(0.0, 0.0, 0.00, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }

        // Check for any out-of-band resize events (mac only)
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            terminal.resize(w as f32, h as f32);
            self.renderer.resize(w as i32, h as i32);
        }

        {
            let glyph_cache = &mut self.glyph_cache;
            // Draw grid
            {
                let _sampler = self.meter.sampler();

                let size_info = terminal.size_info().clone();
                self.renderer.with_api(&size_info, |mut api| {
                    // Draw the grid
                    api.render_grid(&terminal.render_grid(), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                self.renderer.with_api(terminal.size_info(), |mut api| {
                    api.render_string(&timing[..], glyph_cache, &color);
                });
            }
        }

        // Unlock the terminal mutex
        drop(terminal);
        self.window.swap_buffers().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;
extern crate quack;

use std::cell::RefCell;
use sdl2_window::Sdl2Window;
use opengl_graphics::{
    Gl,
};

use std::io;
use std::io::{File};
use std::time::duration::Duration;
use quack::Set;
use input::keyboard::Key;
use input::Button;

use vm::Vm;

mod error;
mod ops;
mod vm;

fn main() {
    let mut vm = Vm::new();

    let roms = [
        "IBM Logo.ch8",           // 0
        "Chip8 Picture.ch8",      // 1
        "Fishie [Hap, 2005].ch8", // 2
        "zerod.ch8",              // 3
        "sierp.ch8",              // 4
        "pong.ch8",               // 5
    ];
    let rom_path = Path::new(format!("/Users/jakerr/Downloads/{}", roms[5]));

    let mut rom_file = File::open(&rom_path).unwrap();

    match vm.load_rom(&mut rom_file) {
        Ok(size) => println!("Loaded rom size: {}", size),
        Err(e) => println!("Error loading rom: {}", e)
    }

    let mut dump_file = File::create(&Path::new("/Users/jakerr/tmp/dump.ch8ram")).unwrap();
    vm.dump_ram(&mut dump_file);

    let (width, height) = (800, 400);
    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        event::WindowSettings {
            title: "Chip8".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let ref mut gl = Gl::new(opengl);
    let window = RefCell::new(window);

    fn keymap(k: Option<Button>) -> Option<u8> {
        use input::Key::*;
        if let Some(Button::Keyboard(k)) = k {
            return match k {
                D1 => Some(0x1),
                D2 => Some(0x2),
                D3 => Some(0x3),

                Q  => Some(0x4),
                W  => Some(0x5),
                E  => Some(0x6),

                A  => Some(0x7),
                S  => Some(0x8),
                D  => Some(0x9),

                Z  => Some(0xA),
                X  => Some(0x0),
                C  => Some(0xB),

                D4 => Some(0xC),
                R  => Some(0xD),
                F  => Some(0xE),
                V  => Some(0xF),

                _ => None
            }
        }
        return None
    }

    for e in event::events(&window) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            vm.step(args.dt as f32);
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |&mut: c, gl| {
                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
                let mut r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
                let off = Color([0.0, 0.0, 0.0, 1.0]);
                let on = Color([1.0, 1.0, 1.0, 1.0]);

                let w = args.width as f64 / 64.0;
                let h = args.height as f64 / 32.0;

                for (y,row) in vm.screen_rows().enumerate() {
                    for (x,byte) in row.iter().enumerate() {
                        let x = x as f64 * w;
                        let y = y as f64 * h;
                        r.set(match *byte { 0 => off, _ => on })
                        .draw([x, y, w, h], &c, gl);
                    }
                }
            });
        }
        if let Some(keynum) = keymap(e.press_args()) {
            vm.set_key(keynum);
        }
        if let Some(keynum) = keymap(e.release_args()) {
            vm.unset_key(keynum);
        }
    }
}
<commit_msg>Lock VM to some multiple of simulation updates<commit_after>extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;
extern crate quack;

use std::cell::RefCell;
use sdl2_window::Sdl2Window;
use opengl_graphics::{
    Gl,
};

use std::io;
use std::io::{File};
use std::time::duration::Duration;
use quack::Set;
use input::keyboard::Key;
use input::Button;

use vm::Vm;

mod error;
mod ops;
mod vm;

const VM_STEPS_PER_UPDATE: u8 = 5;

fn main() {
    let mut vm = Vm::new();

    let roms = [
        "IBM Logo.ch8",           // 0
        "Chip8 Picture.ch8",      // 1
        "Fishie [Hap, 2005].ch8", // 2
        "zerod.ch8",              // 3
        "sierp.ch8",              // 4
        "pong.ch8",               // 5
    ];
    let rom_path = Path::new(format!("/Users/jakerr/Downloads/{}", roms[5]));

    let mut rom_file = File::open(&rom_path).unwrap();

    match vm.load_rom(&mut rom_file) {
        Ok(size) => println!("Loaded rom size: {}", size),
        Err(e) => println!("Error loading rom: {}", e)
    }

    let mut dump_file = File::create(&Path::new("/Users/jakerr/tmp/dump.ch8ram")).unwrap();
    vm.dump_ram(&mut dump_file);

    let (width, height) = (800, 400);
    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        event::WindowSettings {
            title: "Chip8".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let ref mut gl = Gl::new(opengl);
    let window = RefCell::new(window);

    fn keymap(k: Option<Button>) -> Option<u8> {
        use input::Key::*;
        if let Some(Button::Keyboard(k)) = k {
            return match k {
                D1 => Some(0x1),
                D2 => Some(0x2),
                D3 => Some(0x3),

                Q  => Some(0x4),
                W  => Some(0x5),
                E  => Some(0x6),

                A  => Some(0x7),
                S  => Some(0x8),
                D  => Some(0x9),

                Z  => Some(0xA),
                X  => Some(0x0),
                C  => Some(0xB),

                D4 => Some(0xC),
                R  => Some(0xD),
                F  => Some(0xE),
                V  => Some(0xF),

                _ => None
            }
        }
        return None
    }

    for e in event::events(&window) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            let ddt = args.dt / VM_STEPS_PER_UPDATE as f64;
            for i in 0..VM_STEPS_PER_UPDATE {
                vm.step(ddt as f32);
            }
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |&mut: c, gl| {
                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
                let mut r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
                let off = Color([0.0, 0.0, 0.0, 1.0]);
                let on = Color([1.0, 1.0, 1.0, 1.0]);

                let w = args.width as f64 / 64.0;
                let h = args.height as f64 / 32.0;

                for (y,row) in vm.screen_rows().enumerate() {
                    for (x,byte) in row.iter().enumerate() {
                        let x = x as f64 * w;
                        let y = y as f64 * h;
                        r.set(match *byte { 0 => off, _ => on })
                        .draw([x, y, w, h], &c, gl);
                    }
                }
            });
        }
        if let Some(keynum) = keymap(e.press_args()) {
            vm.set_key(keynum);
        }
        if let Some(keynum) = keymap(e.release_args()) {
            vm.unset_key(keynum);
        }
    }
}
<|endoftext|>