<commit_before>use std::io;

#[derive(Debug, PartialEq)]
enum Token {
    LParen,
    RParen,
    Plus,
    Minus,

    Symbol(String),
    Number(i32),
    EOF,
}

pub struct LexerState {
    s: String,
    pos: usize,
}

fn get_token(ls: &mut LexerState) -> Token {
    let mut iter = ls.s[ls.pos..].chars().peekable();
    while let Some(&c) = iter.peek() {
        if c.is_numeric() {
            let mut acc = String::new();
            let mut n = c;
            while n.is_numeric() {
                acc.push(n);
                iter.next();
                ls.pos += 1;
                n = match iter.peek() {
                    Some(&x) => x,
                    None => break,
                };
            }
            return Token::Number(acc.parse().unwrap());
        }
        else if c.is_alphabetic() {
            let mut acc = String::new();
            let mut s = c;
            while s.is_alphanumeric() {
                acc.push(s);
                iter.next();
                ls.pos += 1;
                s = match iter.peek() {
                    Some(&x) => x,
                    None => break,
                };
            }
            return Token::Symbol(acc);
        }
        else {
            match c {
                ' ' => {
                    iter.next();
                    ls.pos += 1;
                    continue
                },
                '(' => {
                    iter.next();
                    ls.pos += 1;
                    return Token::LParen
                },
                ')' => {
                    iter.next();
                    ls.pos += 1;
                    return Token::RParen
                },
                '+' => {
                    iter.next();
                    ls.pos += 1;
                    return Token::Plus
                },
                '-' => {
                    iter.next();
                    ls.pos += 1;
                    return Token::Minus
                },
                _ => return Token::EOF,
            }
        }
    }
    return Token::EOF;
}

fn read_input() -> io::Result<()> {
    let mut input = String::new();

    try!(io::stdin().read_line(&mut input));

    let mut lexer = LexerState {
        s: input,
        pos: 0};

    let mut tok = get_token(&mut lexer);
    while tok != Token::EOF {
        println!("get_token: {:?}", tok);
        tok = get_token(&mut lexer);
    }

    Ok(())
}

fn main() {
    read_input();
}
<commit_msg>WIP: parser<commit_after>use std::io;

#[derive(Debug, PartialEq, Clone)]
enum Token {
    LParen,
    RParen,
    Symbol(String),
    Number(i32),
    EOF,
}

pub struct LexerState {
    s: String,
    pos: usize,
    tok_buf: Option<Token>,
}

#[derive(Debug)]
enum SExpr {
    Symbol(String),
    Number(i32),
    List(Vec<SExpr>),
}

fn unread(ls: &mut LexerState, tok: Token) {
    if let Some(_) = ls.tok_buf {
        println!("error: unread buffer full");
    }
    else {
        ls.tok_buf = Some(tok)
    }
}

fn is_valid_symbol_start(c: char) -> bool {
    // TODO: avoid allocatiing this in each call
    let SymbolStartChars = vec!['+', '-', '*', '/'];

    let mut ret = false;
    if c.is_alphabetic() { ret = true; }
    else {
        for s in SymbolStartChars {
            if c == s { ret = true; break; }
            else { continue; }
        }
    }

    return ret;
}

fn get_token(ls: &mut LexerState) -> Token {
    if let Some(tok) = ls.tok_buf.clone() {
        ls.tok_buf = None;
        return tok;
    }
    else {
        let mut iter = ls.s[ls.pos..].chars().peekable();
        while let Some(&c) = iter.peek() {
            if c.is_numeric() {
                let mut acc = String::new();
                let mut n = c;
                while n.is_numeric() {
                    acc.push(n);
                    iter.next();
                    ls.pos += 1;
                    n = match iter.peek() {
                        Some(&x) => x,
                        None => break,
                    };
                }
                return Token::Number(acc.parse().unwrap());
            }
            else if is_valid_symbol_start(c) {
                let mut acc = String::new();
                let mut s = c;
                while (s.is_alphanumeric() ||
                       is_valid_symbol_start(s)) {
                    acc.push(s);
                    iter.next();
                    ls.pos += 1;
                    s = match iter.peek() {
                        Some(&x) => x,
                        None => break,
                    };
                }
                return Token::Symbol(acc);
            }
            else {
                match c {
                    ' ' => {
                        iter.next();
                        ls.pos += 1;
                        continue
                    },
                    '(' => {
                        iter.next();
                        ls.pos += 1;
                        return Token::LParen
                    },
                    ')' => {
                        iter.next();
                        ls.pos += 1;
                        return Token::RParen
                    },
                    _ => panic!("unexpected char: {}", c),
                }
            }
        }
        return Token::EOF;
    }
}

fn get_list(ls: &mut LexerState) -> Vec<SExpr> {
    match get_expr(ls) {
        exp => match get_token(ls) {
            Token::RParen => return vec![exp],
            tok => {
                unread(ls, tok);
                let mut seq = get_list(ls);
                seq.insert(0, exp);
                return seq;
            },
        },
    }
}

fn get_expr(ls: &mut LexerState) -> SExpr {
    match get_token(ls) {
        Token::Symbol(s) => return SExpr::Symbol(s),
        Token::Number(n) => return SExpr::Number(n),
        Token::LParen => {
            return SExpr::List(get_list(ls));
        },
        Token::RParen => panic!("unmatched ')'"),
        _ => return SExpr::Number(32),
    }
}

fn read_input() -> io::Result<()> {
    let mut input = String::new();

    try!(io::stdin().read_line(&mut input));

    let mut lexer = LexerState {
        s: input,
        pos: 0,
        tok_buf: None,
    };

    println!("{:?}", get_expr(&mut lexer));

    Ok(())
}

fn main() {
    read_input();
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    rustwlc::log_set_handler(log_callback);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

extern fn log_callback(log_type: LogType, text: *const libc::c_char) {
    let string_text = rustwlc::pointer_to_string(text);
    println!("Wlc Log {:?}: {}", log_type, string_text);
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: *const Size, new_size_ptr: *const Size) {
    unsafe {
        println!("output_resolution: {:?} from  {:?} to {:?}",
                 output, &*old_size_ptr, &*new_size_ptr);
    }
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: *const Geometry) {
    unsafe {
        println!("view_request_geometry: {:?} wants {:?}", view, &*geometry);
        view.set_geometry(0, geometry);
        render_output(view.get_output());
    }
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: *const Point) {
    //println!("view_request_move: to {}, start interactive mode.", &*dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: *const Point) {
    unsafe {
        println!("view_request_resize: size {:?}, to {}, start interactive mode.",
                 edge, &*location);
    }
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: *const KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    unsafe {
        use std::process::{Command};
        println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
                 time, &*mods_ptr, key, state);
        if state == KeyState::Pressed { return false; }
        if key == 67 {
            println!("Preparing to open the terminal...");
            rustwlc::exec("/bin/weston-terminal".to_string(),
                          vec!["/bin/weston-terminal".to_string()]);
        }
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: *const KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: *const Point) -> bool {
    unsafe {
        println!("pointer_button: pressed {} at {}", key, &*point_ptr);
        if state == ButtonState::Pressed {
            view.focus();
        }
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: *const KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point_ptr: *const Point) {
    unsafe { pointer::set_position(&*point_ptr); }
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: *const KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: *const Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: *const LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: *const LibinputDevice) {
    println!("input_destroyed");
}
<commit_msg>Fixed the process spawning bug<commit_after>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    rustwlc::log_set_handler(log_callback);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

extern fn log_callback(log_type: LogType, text: *const libc::c_char) {
    let string_text = rustwlc::pointer_to_string(text);
    println!("Wlc Log {:?}: {}", log_type, string_text);
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: *const Size, new_size_ptr: *const Size) {
    unsafe {
        println!("output_resolution: {:?} from  {:?} to {:?}",
                 output, &*old_size_ptr, &*new_size_ptr);
    }
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: *const Geometry) {
    unsafe {
        println!("view_request_geometry: {:?} wants {:?}", view, &*geometry);
        view.set_geometry(0, geometry);
        render_output(view.get_output());
    }
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: *const Point) {
    //println!("view_request_move: to {}, start interactive mode.", &*dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: *const Point) {
    unsafe {
        println!("view_request_resize: size {:?}, to {}, start interactive mode.",
                 edge, &*location);
    }
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: *const KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    unsafe {
        use std::process::{Command};
        println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
                 time, &*mods_ptr, key, state);
        if state == KeyState::Pressed { return false; }
        if key == 67 {
            println!("Preparing to open the terminal...");
        let mut child = Command::new("/bin/weston-terminal").spawn()
            .unwrap_or_else(|e| { println!("Error spawning child: {}", e); panic!("1") });
        }
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: *const KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: *const Point) -> bool {
    unsafe {
        println!("pointer_button: pressed {} at {}", key, &*point_ptr);
        if state == ButtonState::Pressed {
            view.focus();
        }
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: *const KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point_ptr: *const Point) {
    unsafe { pointer::set_position(&*point_ptr); }
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: *const KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: *const Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: *const LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: *const LibinputDevice) {
    println!("input_destroyed");
}
<|endoftext|>


<commit_before>struct Philosopher {
    name: String
}

impl Philosopher {
    fn new(name: &str) -> Philosopher {
        Philosopher {
            name: name.to_string()
        }
    }

    fn eat(&self) {
        println!("{} is done eating.", self.name);
    }
}

fn main() {
    let p1 = Philosopher::new("Judith Butler");
    let p2 = Philosopher::new("Gilles Deleuze");
    let p3 = Philosopher::new("Karl Marx");
    let p4 = Philosopher::new("Emma Goldman");
    let p5 = Philosopher::new("Michel Foucault");
}
<commit_msg>Move the 5 philosophers into a vector<commit_after>struct Philosopher {
    name: String
}

impl Philosopher {
    fn new(name: &str) -> Philosopher {
        Philosopher {
            name: name.to_string()
        }
    }

    fn eat(&self) {
        println!("{} is done eating.", self.name);
    }
}

fn main() {
    let philosophers = vec![
        Philosopher::new("Judith Butler"),
        Philosopher::new("Gilles Deleuze"),
        Philosopher::new("Karl Marx"),
        Philosopher::new("Emma Goldman"),
        Philosopher::new("Michel Foucault"),
    ];
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let mut x0 = start.x();
        let mut y0 = start.y();
        let mut x1 = end.x();
        let mut y1 = end.y();

        let steep = (y1 - y0).abs() > (x1 - x0).abs();

        if steep {
            std::mem::swap(&mut x0, &mut y0);
            std::mem::swap(&mut x1, &mut y1);
        }

        let reverse = x0 > x1;

        if reverse {
            std::mem::swap(&mut x0, &mut x1);
            std::mem::swap(&mut y0, &mut y1);
        }

        let dx = x1 - x0;
        let dy = (y1 - y0).abs();

        let mut err = dx / 2;
        let mut y = y0;
        let ystep = match y0.cmp(&y1) {
            Ordering::Less => 1,
            _ => -1
        };

        for x in x0..x1 {
            if steep {
                self.draw_point(Point::new(y, x)).unwrap();
            } else {
                self.draw_point(Point::new(x, y)).unwrap();
            }

            err -= dy;

            if err < 0 {
                y += ystep;
                err += dx;
            }
        }

        self.set_draw_color(current_color);
    }
}

fn main() {
    let (width, height) = (600, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Implement dummy-fresh triangle rasterization algorithm from my head<commit_after>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

fn sort_points_by_y(points: &mut Vec<Point>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y() < points[j + 1].y() {
                points.swap(j, j + 1);
            }
        }
    }
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
    fn triangle(&mut self, Point, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let mut x0 = start.x();
        let mut y0 = start.y();
        let mut x1 = end.x();
        let mut y1 = end.y();

        let steep = (y1 - y0).abs() > (x1 - x0).abs();

        if steep {
            std::mem::swap(&mut x0, &mut y0);
            std::mem::swap(&mut x1, &mut y1);
        }

        let reverse = x0 > x1;

        if reverse {
            std::mem::swap(&mut x0, &mut x1);
            std::mem::swap(&mut y0, &mut y1);
        }

        let dx = x1 - x0;
        let dy = (y1 - y0).abs();

        let mut err = dx / 2;
        let mut y = y0;
        let ystep = match y0.cmp(&y1) {
            Ordering::Less => 1,
            _ => -1
        };

        for x in x0..x1 {
            if steep {
                self.draw_point(Point::new(y, x)).unwrap();
            } else {
                self.draw_point(Point::new(x, y)).unwrap();
            }

            err -= dy;

            if err < 0 {
                y += ystep;
                err += dx;
            }
        }

        self.set_draw_color(current_color);
    }

    fn triangle(&mut self, p0: Point, p1: Point, p2: Point, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let horizon = get_line_points(points[1], points[2]);

        for l in 0..horizon.len() {
            self.line(points[0], horizon[l], c);
        }
    }
}

fn main() {
    let (width, height) = (600, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.triangle(Point::new(20, 50), Point::new(100, 200), Point::new(40, 300), Color::RGB(0, 255, 0));

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>/*
  Rust is an Expression-Based Systems language.
  Declare main function
*/
fn main() {

    // Metaprogramming calling a macro and passing staticaly allocated string arg
    println!("Hello, world!");

    /*
      Variable binding expression.
      <let expression> is Full Pattern for Pattern Matching.
      Rust's Type Inference automatically determines an expression's Type.
      Alternatively be explicit and supply an expression's Type after a colon.
      Or simply annotate the Type in a comment to understand the Type Rust infers.
      Rust Bindings are immutable by Default.
      Mutable Bindings require 'mut' prefix for Type Safety.
    */
    let a: i32 = 5; // assign immutable binding 'a' with Type i32 and Value 5

    // If statement based on Branch concept
    if a == 5 {
      println!("x is five");
    } else {
      println!("x is not five");
    }

    let (x, y, z) = (1, 2, 3);  // assign immutable bindings x, y, z to 1, 2, 3

    let mut b: i32 = 10; // assign mutable binding 'b'
    b = 20; // re-assign to new Value

    /*
      Rust's 'If' is an Expression. It returns a value to initialise
      the 'Let' binding ("Declaration Statement") with. 'Let' is assigned an Expression.
      Assignment to an already bound variable is an Expression.
      Assignment Value in Rust is the special Unit Type () in Rust's Type System.
      In other languages 'If' is a Statements (does not return value).

      Rust's "Expression Statement" converts an Expression into a Statement.
      Semi-colons separate each Expression.
      Semi-colons convert Expression into Statement, throws Value away, returns Unit Type ()
      (causing Type Error when expect a different Type such as i32 to be valid)
    */
    let c: i32 = if b == 20 { 25 } else { 15 };  // Explicitely specify 'c' as of Integer Type
    println!("b is: {}", b); // Interpret interpolation with moustaches
    println!("c is: {}", c);

    incr(b, c); // Call Fn passing Args
    print_sum(b, c); // Call Fn passing Args
}

// All control paths must Return a Value
fn incr(m: i32, n: i32) -> i32 {
    if n < m {
      return n; // Early Return
    } else {
      println!("incrementing n from: {}", n);
      return n + 10;
    }
}

/*
  Rust forces Declare expected Type of incoming Fn Args. Type Inference in Fn body.
  Rust allows Declaration expected Type of outgoing Return Value after '->'
*/
fn print_sum(m: i32, n: i32) -> () { // Return the Unit Type () (aka nil)
    if m < n {
      println!("sum with m < n is: {}", m + n);
    } else {
      println!("sum with m >= n is: {}", m + n);
    }
}<commit_msg>Tuples<commit_after>/*
  Rust is an Expression-Based Systems language.
  Declare main function
*/
fn main() {

    // Metaprogramming calling a macro and passing staticaly allocated string arg
    println!("Hello, world!");

    /*
      Variable binding expression.
      <let expression> is Full Pattern for Pattern Matching.
      Rust's Type Inference automatically determines an expression's Type.
      Alternatively be explicit and supply an expression's Type after a colon.
      Or simply annotate the Type in a comment to understand the Type Rust infers.
      Rust Bindings are immutable by Default.
      Mutable Bindings require 'mut' prefix for Type Safety.
    */
    let a: i32 = 5; // assign immutable binding 'a' with Type i32 and Value 5

    // If statement based on Branch concept
    if a == 5 {
      println!("x is five");
    } else {
      println!("x is not five");
    }

    let (x, y, z) = (1, 2, 3);  // assign immutable bindings x, y, z to 1, 2, 3

    let mut b: i32 = 10; // assign mutable binding 'b'
    b = 20; // re-assign to new Value

    /*
      Rust's 'If' is an Expression. It returns a value to initialise
      the 'Let' binding ("Declaration Statement") with. 'Let' is assigned an Expression.
      Assignment to an already bound variable is an Expression.
      Assignment Value in Rust is the special Unit Type () in Rust's Type System.
      In other languages 'If' is a Statements (does not return value).

      Rust's "Expression Statement" converts an Expression into a Statement.
      Semi-colons separate each Expression.
      Semi-colons convert Expression into Statement, throws Value away, returns Unit Type ()
      (causing Type Error when expect a different Type such as i32 to be valid)
    */
    let c: i32 = if b == 20 { 25 } else { 15 };  // Explicitely specify 'c' as of Integer Type
    println!("b is: {}", b); // Interpret interpolation with moustaches
    println!("c is: {}", c);

    incr(b, c); // Call Fn passing Args
    print_sum(b, c); // Call Fn passing Args

    // Compound Data Structure Type Tuple is simple fixed size ordered list where &str is String Slice
    let tuple1: (i32, &str) = (1, "hello"); // Mutable. Type annotated. Without: let x = (1, "hello");
    let mut tuple2: (i32, i32) = (1, 2); // Type annotated. Without: let x = (1, "hello");
    let tuple3: (i32, i32) = (3, 4);

    if tuple2 != tuple3 {
        tuple2 = tuple3; // Assign Tuple to another Mutable Tuple (with same Arity and Types)
        println!("tuple2 and tuple3 not equal so assigning");
    } else {
        println!("tuple2 and tuple3 do not have same Arity, Types, Order, and Value, not assigning");
    }

    /*
      Destructuring Let (access parameters of Tuple).
      Let statement performs Multiple Bindings assignments when LHS and RHS Pattern Match
    */
    let (t1, t2) = tuple2;

    println!("t1 and t2 is {}", t1 + t2); // Note: Expects t1 and t2 to be same Type

    // Tuples to return Multiple Values from a Function
    let (tnt1, tnt2) = next_two(5);
    println!("tnt1, tnt2 = {}, {}", tnt1, tnt2);
}

// Returned Tuple is a Single Value (containing Multiple Values)
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }

// All control paths must Return a Value
fn incr(m: i32, n: i32) -> i32 {
    if n < m {
      return n; // Early Return
    } else {
      println!("incrementing n from: {}", n);
      return n + 10;
    }
}

/*
  Rust forces Declare expected Type of incoming Fn Args. Type Inference in Fn body.
  Rust allows Declaration expected Type of outgoing Return Value after '->'
*/
fn print_sum(m: i32, n: i32) -> () { // Return the Unit Type () (aka nil)
    if m < n {
      println!("sum with m < n is: {}", m + n);
    } else {
      println!("sum with m >= n is: {}", m + n);
    }
}<|endoftext|>


<commit_before>//!                             The Unlicense
//! This is free and unencumbered software released into the public domain.
//!
//! Anyone is free to copy, modify, publish, use, compile, sell, or
//! distribute this software, either in source code form or as a compiled
//! binary, for any purpose, commercial or non-commercial, and by any
//! means.
//!
//! In jurisdictions that recognize copyright laws, the author or authors
//! of this software dedicate any and all copyright interest in the
//! software to the public domain. We make this dedication for the benefit
//! of the public at large and to the detriment of our heirs and
//! successors. We intend this dedication to be an overt act of
//! relinquishment in perpetuity of all present and future rights to this
//! software under copyright law.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//! EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//! MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//! IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
//! OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
//! ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//! OTHER DEALINGS IN THE SOFTWARE.
//!
//! For more information, please refer to <http://unlicense.org>
//!

extern crate iron;
extern crate router;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate hyper_rustls;
extern crate urlencoded;
extern crate persistent;
extern crate lru_cache;
extern crate time;
extern crate crypto_hash;

use std::vec::Vec;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::io::Read;
use std::collections::HashMap;
use std::option::Option;
use std::result::Result;

use hyper::client::{Client as HyperClient, Response as HyperResponse};
use hyper::net::HttpsConnector as HyperHttpsConnector;
use hyper::status::StatusCode as HyperStatusCode;
use hyper::header as hyper_header;
use hyper_rustls::TlsClient as HyperRustlsClient;

use iron::{IronResult, IronError, Iron};
use iron::{Request as IronRequest, Response as IronResponse, Chain as IronChain,
           Plugin as IronPlugin};
use iron::{AfterMiddleware, Handler};
use iron::typemap::Key;

use router::{Router, NoRoute};
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
use persistent::Write;

use regex::Regex;
use lru_cache::LruCache;
use crypto_hash::{Algorithm as HashAlgorithm, hex_digest};

header! { (XPoweredBy, "X-Powered-By") => [String] }

fn verify_md5(md5: &str) -> bool {
    lazy_static! {
        static ref MD5_RE: Regex = Regex::new("^[0-9a-f]{32}$").unwrap();
    }

    MD5_RE.is_match(md5)
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct CacheControlKey {
    email_md5: String,
    size: Option<i64>,
    default: Option<String>,
}

impl CacheControlKey {
    fn from_request(req: &mut IronRequest) -> Result<CacheControlKey, IronResponse> {
        let email_md5 = req.extensions
            .get::<Router>()
            .unwrap()
            .find("email_md5")
            .unwrap_or("")
            .to_lowercase();

        if !verify_md5(email_md5.as_str()) {
            return Err(IronResponse::with((HyperStatusCode::NotFound)));
        }

        let maybe_query = req.get::<UrlEncodedQuery>()
            .map(|val| Some(val))
            .unwrap_or_else(|err: UrlDecodingError| {
                match err {
                    UrlDecodingError::EmptyQuery => Some(HashMap::new()),
                    _ => None,
                }
            });

        let query = match maybe_query {
            Some(m) => m,
            None => return Err(IronResponse::with((HyperStatusCode::BadRequest))),
        };

        let size_str = query.get("s")
            .map(|s_vec| s_vec.clone())
            .map(|s_vec| { if s_vec.len() > 0 { Some(s_vec) } else { None } })
            .unwrap_or(None)
            .map(|s_vec| s_vec[0].clone());

        let default = query.get("d")
            .map(|d_vec| d_vec.clone())
            .map(|d_vec| { if d_vec.len() > 0 { Some(d_vec) } else { None } })
            .unwrap_or(None)
            .map(|d_vec| d_vec[0].clone());

        let size: Option<i64> = match size_str {
            Some(m) => {
                match m.parse::<i64>() {
                    Ok(m) => Some(m),
                    Err(_) => return Err(IronResponse::with((HyperStatusCode::BadRequest))),
                }
            }
            None => None,
        };

        Ok(CacheControlKey {
            email_md5: email_md5,
            size: size,
            default: default,
        })
    }
}

#[derive(Clone)]
struct CacheControlData {
    pub etag: hyper_header::EntityTag,
    pub last_modified: hyper_header::HttpDate,
    pub content_type: hyper_header::ContentType,
    pub content_disposition: Option<hyper_header::ContentDisposition>,
    pub cache_control: hyper_header::CacheControl,
    pub expires: hyper_header::HttpDate,
}

impl CacheControlData {
    fn from_response(res: &HyperResponse, res_body: &[u8]) -> AvatarResult<CacheControlData> {
        let etag = hyper_header::EntityTag::strong(hex_digest(HashAlgorithm::SHA256,
                                                              res_body.to_vec()));
        let last_modified = res.headers
            .get::<hyper_header::LastModified>()
            .map(|m| m.deref().clone())
            .unwrap_or_else(|| hyper_header::HttpDate(time::now()));

        let content_type = try!(res.headers
            .get::<hyper_header::ContentType>()
            .map(|m| m.clone())
            .ok_or_else(|| IronResponse::with((HyperStatusCode::BadGateway))));

        let content_disposition =
            res.headers.get::<hyper_header::ContentDisposition>().map(|m| m.clone());
        let cache_control =
            hyper_header::CacheControl(vec![hyper_header::CacheDirective::MaxAge(600 as u32)]);
        let expires = hyper_header::HttpDate(time::now() + time::Duration::minutes(10));

        Ok(CacheControlData {
            etag: etag,
            last_modified: last_modified,
            content_type: content_type,
            content_disposition: content_disposition,
            cache_control: cache_control,
            expires: expires,
        })
    }

    fn set_cache_headers(&self, mut res: &mut IronResponse) {
        res.headers.set(hyper_header::ETag(self.etag.clone()));
        res.headers.set(hyper_header::LastModified(self.last_modified.clone()));
        if let Some(m) = self.content_disposition.clone() {
            res.headers.set(m);
        }
        res.headers.set(self.cache_control.clone());
        res.headers.set(hyper_header::Expires(self.expires.clone()));

    }
}

#[derive(Clone)]
struct Cache;
impl Key for Cache {
    type Value = LruCache<CacheControlKey, CacheControlData>;
}

struct Avatar {
    pub buf: Vec<u8>,
    pub cc_key: CacheControlKey,
    pub cc_data: CacheControlData,
}

type AvatarResult<T> = Result<T, IronResponse>;

impl Avatar {
    fn make_origin_url(cc_key: &CacheControlKey) -> String {
        let mut origin_url = format!("https://secure.gravatar.com/avatar/{}", cc_key.email_md5);

        let mut params: Vec<String> = Vec::new();

        if let Some(ref m) = cc_key.size {
            params.push(format!("s={}", m));
        }

        if let Some(ref m) = cc_key.default {
            params.push(format!("d={}", m));
        }

        if params.len() > 0 {
            origin_url.push_str("?");
            origin_url.push_str(params.join("&").as_str());
        }

        origin_url
    }

    pub fn from_response(res: &mut HyperResponse, cc_key: CacheControlKey) -> AvatarResult<Avatar> {
        if res.status != hyper::Ok {
            return Err(IronResponse::with((HyperStatusCode::BadGateway)));
        }

        let mut avatar_body: Vec<u8> = Vec::new();

        try!(res.read_to_end(&mut avatar_body)
            .map_err(|_| IronResponse::with((HyperStatusCode::BadGateway))));

        let cc_data = try!(CacheControlData::from_response(res, avatar_body.as_slice()));

        Ok(Avatar {
            buf: avatar_body,
            cc_key: cc_key,
            cc_data: cc_data,
        })

    }

    pub fn fetch(cc_key: CacheControlKey) -> AvatarResult<Avatar> {
        lazy_static! {
            static ref HYPER_CLIENT: HyperClient = HyperClient::with_connector(HyperHttpsConnector::new(HyperRustlsClient::new()));
        }

        let origin_url = Avatar::make_origin_url(&cc_key);

        let mut origin_res = try!(HYPER_CLIENT.get(origin_url.as_str())
            .send()
            .map_err(|_| IronResponse::with((HyperStatusCode::BadGateway))));

        Avatar::from_response(&mut origin_res, cc_key)
    }
}

struct MainHandler;

impl MainHandler {
    fn read_from_cache(&self,
                       cc_key: &CacheControlKey,
                       cache_mutex: &Arc<Mutex<LruCache<CacheControlKey, CacheControlData>>>)
                       -> Option<CacheControlData> {
        let mut cache = cache_mutex.lock().unwrap();

        let cc_data = match cache.get_mut(cc_key).map(|m| m.clone()) {
            Some(m) => m,
            None => return None,
        };

        if cc_data.expires > hyper_header::HttpDate(time::now()) {
            Some(cc_data)
        } else {
            cache.remove(cc_key);
            None
        }
    }

    fn response_with_200(&self, avatar: &Avatar) -> IronResult<IronResponse> {
        let mut res = IronResponse::with((avatar.cc_data.content_type.deref().clone(),
                                          HyperStatusCode::Ok,
                                          avatar.buf.clone()));

        avatar.cc_data.set_cache_headers(&mut res);
        Ok(res)

    }

    fn response_with_304(&self, cc_data: &CacheControlData) -> IronResult<IronResponse> {
        let mut res = IronResponse::with((cc_data.content_type.deref().clone(),
                                          HyperStatusCode::NotModified));

        cc_data.set_cache_headers(&mut res);

        Ok(res)
    }
}

impl Handler for MainHandler {
    fn handle(&self, mut req: &mut IronRequest) -> IronResult<IronResponse> {
        let cache_mutex = req.get::<Write<Cache>>().unwrap();

        let cc_key = match CacheControlKey::from_request(&mut req) {
            Ok(v) => v,
            Err(res) => return Ok(res),
        };

        let maybe_if_modified_since = req.headers.get::<hyper_header::IfModifiedSince>();
        let maybe_if_none_match = req.headers.get::<hyper_header::IfNoneMatch>();

        if let Some(if_none_match) = maybe_if_none_match {
            // Prefer ETag.
            if let Some(cc_data) = self.read_from_cache(&cc_key, &cache_mutex) {
                if let &hyper_header::IfNoneMatch::Items(ref items) = if_none_match {
                    if items.as_slice().contains(&cc_data.etag) {
                        return self.response_with_304(&cc_data);
                    }
                }
            }
        } else if let Some(if_modified_since) = maybe_if_modified_since {
            if let Some(cc_data) = self.read_from_cache(&cc_key, &cache_mutex) {
                if if_modified_since.deref() == &cc_data.last_modified {
                    return self.response_with_304(&cc_data);
                }
            }
        }

        let avatar = match Avatar::fetch(cc_key) {
            Ok(v) => v,
            Err(res) => return Ok(res),
        };

        let res_result = self.response_with_200(&avatar);
        {
            let mut cache = cache_mutex.lock().unwrap();

            cache.insert(avatar.cc_key, avatar.cc_data);
        }
        res_result
    }
}

struct CustomErrorMsg;

impl CustomErrorMsg {
    fn alter_response(&self, res: IronResponse) -> IronResponse {
        if res.status == Some(HyperStatusCode::NotFound) {
            IronResponse::with((HyperStatusCode::NotFound, "HTTP 404: Not Found."))

        } else if res.status == Some(HyperStatusCode::BadRequest) {
            IronResponse::with((HyperStatusCode::BadRequest, "HTTP 400: Bad Request."))

        } else if res.status == Some(HyperStatusCode::BadGateway) {
            IronResponse::with((HyperStatusCode::BadGateway, "HTTP 502: Bad Gateway."))

        } else {
            res

        }
    }
}

impl AfterMiddleware for CustomErrorMsg {
    fn after(&self, _: &mut IronRequest, res: IronResponse) -> IronResult<IronResponse> {
        Ok(self.alter_response(res))
    }

    fn catch(&self, _: &mut IronRequest, err: IronError) -> IronResult<IronResponse> {
        let res = err.response;
        let res = self.alter_response(res);

        if let Some(_) = err.error.downcast::<NoRoute>() {
            return Ok(res);
        }

        Err(IronError {
            error: err.error,
            response: res,
        })
    }
}

struct AddXPoweredBy;

impl AddXPoweredBy {
    fn add_header(&self, res: &mut IronResponse) {
        res.headers.set(XPoweredBy("Rust".to_owned()));
    }
}

impl AfterMiddleware for AddXPoweredBy {
    fn after(&self, _: &mut IronRequest, mut res: IronResponse) -> IronResult<IronResponse> {
        self.add_header(&mut res);

        Ok(res)
    }

    fn catch(&self, _: &mut IronRequest, err: IronError) -> IronResult<IronResponse> {
        let mut res = err.response;
        let inner_err = err.error;
        self.add_header(&mut res);

        Err(IronError {
            error: inner_err,
            response: res,
        })
    }
}

fn main() {
    let mut router = Router::new();

    router.get("/avatar/:email_md5", MainHandler, "email_md5");

    let mut chain = IronChain::new(router);
    chain.link_after(CustomErrorMsg);
    chain.link_after(AddXPoweredBy);

    chain.link(Write::<Cache>::both(LruCache::new(102400)));

    Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>Rename CacheControl* to AvatarCache*.<commit_after>//!                             The Unlicense
//! This is free and unencumbered software released into the public domain.
//!
//! Anyone is free to copy, modify, publish, use, compile, sell, or
//! distribute this software, either in source code form or as a compiled
//! binary, for any purpose, commercial or non-commercial, and by any
//! means.
//!
//! In jurisdictions that recognize copyright laws, the author or authors
//! of this software dedicate any and all copyright interest in the
//! software to the public domain. We make this dedication for the benefit
//! of the public at large and to the detriment of our heirs and
//! successors. We intend this dedication to be an overt act of
//! relinquishment in perpetuity of all present and future rights to this
//! software under copyright law.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//! EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//! MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//! IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
//! OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
//! ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//! OTHER DEALINGS IN THE SOFTWARE.
//!
//! For more information, please refer to <http://unlicense.org>
//!

extern crate iron;
extern crate router;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate hyper_rustls;
extern crate urlencoded;
extern crate persistent;
extern crate lru_cache;
extern crate time;
extern crate crypto_hash;

use std::vec::Vec;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::io::Read;
use std::collections::HashMap;
use std::option::Option;
use std::result::Result;

use hyper::client::{Client as HyperClient, Response as HyperResponse};
use hyper::net::HttpsConnector as HyperHttpsConnector;
use hyper::status::StatusCode as HyperStatusCode;
use hyper::header as hyper_header;
use hyper_rustls::TlsClient as HyperRustlsClient;

use iron::{IronResult, IronError, Iron};
use iron::{Request as IronRequest, Response as IronResponse, Chain as IronChain,
           Plugin as IronPlugin};
use iron::{AfterMiddleware, Handler};
use iron::typemap::Key;

use router::{Router, NoRoute};
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
use persistent::Write;

use regex::Regex;
use lru_cache::LruCache;
use crypto_hash::{Algorithm as HashAlgorithm, hex_digest};

header! { (XPoweredBy, "X-Powered-By") => [String] }

fn verify_md5(md5: &str) -> bool {
    lazy_static! {
        static ref MD5_RE: Regex = Regex::new("^[0-9a-f]{32}$").unwrap();
    }

    MD5_RE.is_match(md5)
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct AvatarCacheKey {
    email_md5: String,
    size: Option<i64>,
    default: Option<String>,
}

impl AvatarCacheKey {
    fn from_request(req: &mut IronRequest) -> Result<AvatarCacheKey, IronResponse> {
        let email_md5 = req.extensions
            .get::<Router>()
            .unwrap()
            .find("email_md5")
            .unwrap_or("")
            .to_lowercase();

        if !verify_md5(email_md5.as_str()) {
            return Err(IronResponse::with((HyperStatusCode::NotFound)));
        }

        let maybe_query = req.get::<UrlEncodedQuery>()
            .map(|val| Some(val))
            .unwrap_or_else(|err: UrlDecodingError| {
                match err {
                    UrlDecodingError::EmptyQuery => Some(HashMap::new()),
                    _ => None,
                }
            });

        let query = match maybe_query {
            Some(m) => m,
            None => return Err(IronResponse::with((HyperStatusCode::BadRequest))),
        };

        let size_str = query.get("s")
            .map(|s_vec| s_vec.clone())
            .map(|s_vec| { if s_vec.len() > 0 { Some(s_vec) } else { None } })
            .unwrap_or(None)
            .map(|s_vec| s_vec[0].clone());

        let default = query.get("d")
            .map(|d_vec| d_vec.clone())
            .map(|d_vec| { if d_vec.len() > 0 { Some(d_vec) } else { None } })
            .unwrap_or(None)
            .map(|d_vec| d_vec[0].clone());

        let size: Option<i64> = match size_str {
            Some(m) => {
                match m.parse::<i64>() {
                    Ok(m) => Some(m),
                    Err(_) => return Err(IronResponse::with((HyperStatusCode::BadRequest))),
                }
            }
            None => None,
        };

        Ok(AvatarCacheKey {
            email_md5: email_md5,
            size: size,
            default: default,
        })
    }
}

#[derive(Clone)]
struct AvatarCacheData {
    pub etag: hyper_header::EntityTag,
    pub last_modified: hyper_header::HttpDate,
    pub content_type: hyper_header::ContentType,
    pub content_disposition: Option<hyper_header::ContentDisposition>,
    pub cache_control: hyper_header::CacheControl,
    pub expires: hyper_header::HttpDate,
}

impl AvatarCacheData {
    fn from_response(res: &HyperResponse, res_body: &[u8]) -> AvatarResult<AvatarCacheData> {
        let etag = hyper_header::EntityTag::strong(hex_digest(HashAlgorithm::SHA256,
                                                              res_body.to_vec()));
        let last_modified = res.headers
            .get::<hyper_header::LastModified>()
            .map(|m| m.deref().clone())
            .unwrap_or_else(|| hyper_header::HttpDate(time::now()));

        let content_type = try!(res.headers
            .get::<hyper_header::ContentType>()
            .map(|m| m.clone())
            .ok_or_else(|| IronResponse::with((HyperStatusCode::BadGateway))));

        let content_disposition =
            res.headers.get::<hyper_header::ContentDisposition>().map(|m| m.clone());
        let cache_control =
            hyper_header::CacheControl(vec![hyper_header::CacheDirective::MaxAge(600 as u32)]);
        let expires = hyper_header::HttpDate(time::now() + time::Duration::minutes(10));

        Ok(AvatarCacheData {
            etag: etag,
            last_modified: last_modified,
            content_type: content_type,
            content_disposition: content_disposition,
            cache_control: cache_control,
            expires: expires,
        })
    }

    fn set_cache_headers(&self, mut res: &mut IronResponse) {
        res.headers.set(hyper_header::ETag(self.etag.clone()));
        res.headers.set(hyper_header::LastModified(self.last_modified.clone()));
        if let Some(m) = self.content_disposition.clone() {
            res.headers.set(m);
        }
        res.headers.set(self.cache_control.clone());
        res.headers.set(hyper_header::Expires(self.expires.clone()));

    }
}

#[derive(Clone)]
struct AvatarCache;

impl Key for AvatarCache {
    type Value = LruCache<AvatarCacheKey, AvatarCacheData>;
}

struct Avatar {
    pub buf: Vec<u8>,
    pub ac_key: AvatarCacheKey,
    pub ac_data: AvatarCacheData,
}

type AvatarResult<T> = Result<T, IronResponse>;

impl Avatar {
    fn make_origin_url(ac_key: &AvatarCacheKey) -> String {
        let mut origin_url = format!("https://secure.gravatar.com/avatar/{}", ac_key.email_md5);

        let mut params: Vec<String> = Vec::new();

        if let Some(ref m) = ac_key.size {
            params.push(format!("s={}", m));
        }

        if let Some(ref m) = ac_key.default {
            params.push(format!("d={}", m));
        }

        if params.len() > 0 {
            origin_url.push_str("?");
            origin_url.push_str(params.join("&").as_str());
        }

        origin_url
    }

    pub fn from_response(res: &mut HyperResponse, ac_key: AvatarCacheKey) -> AvatarResult<Avatar> {
        if res.status != hyper::Ok {
            return Err(IronResponse::with((HyperStatusCode::BadGateway)));
        }

        let mut avatar_body: Vec<u8> = Vec::new();

        try!(res.read_to_end(&mut avatar_body)
            .map_err(|_| IronResponse::with((HyperStatusCode::BadGateway))));

        let ac_data = try!(AvatarCacheData::from_response(res, avatar_body.as_slice()));

        Ok(Avatar {
            buf: avatar_body,
            ac_key: ac_key,
            ac_data: ac_data,
        })

    }

    pub fn fetch(ac_key: AvatarCacheKey) -> AvatarResult<Avatar> {
        lazy_static! {
            static ref HYPER_CLIENT: HyperClient = HyperClient::with_connector(HyperHttpsConnector::new(HyperRustlsClient::new()));
        }

        let origin_url = Avatar::make_origin_url(&ac_key);

        let mut origin_res = try!(HYPER_CLIENT.get(origin_url.as_str())
            .send()
            .map_err(|_| IronResponse::with((HyperStatusCode::BadGateway))));

        Avatar::from_response(&mut origin_res, ac_key)
    }
}

struct MainHandler;

impl MainHandler {
    fn read_from_avatar_cache(&self,
                              ac_key: &AvatarCacheKey,
                              avatar_cache_mutex: &Arc<Mutex<LruCache<AvatarCacheKey,
                                                                      AvatarCacheData>>>)
                              -> Option<AvatarCacheData> {
        let mut avatar_cache = avatar_cache_mutex.lock().unwrap();

        let ac_data = match avatar_cache.get_mut(ac_key).map(|m| m.clone()) {
            Some(m) => m,
            None => return None,
        };

        if ac_data.expires > hyper_header::HttpDate(time::now()) {
            Some(ac_data)
        } else {
            avatar_cache.remove(ac_key);
            None
        }
    }

    fn response_with_200(&self, avatar: &Avatar) -> IronResult<IronResponse> {
        let mut res = IronResponse::with((avatar.ac_data.content_type.deref().clone(),
                                          HyperStatusCode::Ok,
                                          avatar.buf.clone()));

        avatar.ac_data.set_cache_headers(&mut res);
        Ok(res)

    }

    fn response_with_304(&self, ac_data: &AvatarCacheData) -> IronResult<IronResponse> {
        let mut res = IronResponse::with((ac_data.content_type.deref().clone(),
                                          HyperStatusCode::NotModified));

        ac_data.set_cache_headers(&mut res);

        Ok(res)
    }
}

impl Handler for MainHandler {
    fn handle(&self, mut req: &mut IronRequest) -> IronResult<IronResponse> {
        let avatar_cache_mutex = req.get::<Write<AvatarCache>>().unwrap();

        let ac_key = match AvatarCacheKey::from_request(&mut req) {
            Ok(v) => v,
            Err(res) => return Ok(res),
        };

        let maybe_if_modified_since = req.headers.get::<hyper_header::IfModifiedSince>();
        let maybe_if_none_match = req.headers.get::<hyper_header::IfNoneMatch>();

        if let Some(if_none_match) = maybe_if_none_match {
            // Prefer ETag.
            if let Some(ac_data) = self.read_from_avatar_cache(&ac_key, &avatar_cache_mutex) {
                if let &hyper_header::IfNoneMatch::Items(ref items) = if_none_match {
                    if items.as_slice().contains(&ac_data.etag) {
                        return self.response_with_304(&ac_data);
                    }
                }
            }
        } else if let Some(if_modified_since) = maybe_if_modified_since {
            if let Some(ac_data) = self.read_from_avatar_cache(&ac_key, &avatar_cache_mutex) {
                if if_modified_since.deref() == &ac_data.last_modified {
                    return self.response_with_304(&ac_data);
                }
            }
        }

        let avatar = match Avatar::fetch(ac_key) {
            Ok(v) => v,
            Err(res) => return Ok(res),
        };

        let res_result = self.response_with_200(&avatar);
        {
            let mut avatar_cache = avatar_cache_mutex.lock().unwrap();

            avatar_cache.insert(avatar.ac_key, avatar.ac_data);
        }
        res_result
    }
}

struct CustomErrorMsg;

impl CustomErrorMsg {
    fn alter_response(&self, res: IronResponse) -> IronResponse {
        if res.status == Some(HyperStatusCode::NotFound) {
            IronResponse::with((HyperStatusCode::NotFound, "HTTP 404: Not Found."))

        } else if res.status == Some(HyperStatusCode::BadRequest) {
            IronResponse::with((HyperStatusCode::BadRequest, "HTTP 400: Bad Request."))

        } else if res.status == Some(HyperStatusCode::BadGateway) {
            IronResponse::with((HyperStatusCode::BadGateway, "HTTP 502: Bad Gateway."))

        } else {
            res

        }
    }
}

impl AfterMiddleware for CustomErrorMsg {
    fn after(&self, _: &mut IronRequest, res: IronResponse) -> IronResult<IronResponse> {
        Ok(self.alter_response(res))
    }

    fn catch(&self, _: &mut IronRequest, err: IronError) -> IronResult<IronResponse> {
        let res = err.response;
        let res = self.alter_response(res);

        if let Some(_) = err.error.downcast::<NoRoute>() {
            return Ok(res);
        }

        Err(IronError {
            error: err.error,
            response: res,
        })
    }
}

struct AddXPoweredBy;

impl AddXPoweredBy {
    fn add_header(&self, res: &mut IronResponse) {
        res.headers.set(XPoweredBy("Rust".to_owned()));
    }
}

impl AfterMiddleware for AddXPoweredBy {
    fn after(&self, _: &mut IronRequest, mut res: IronResponse) -> IronResult<IronResponse> {
        self.add_header(&mut res);

        Ok(res)
    }

    fn catch(&self, _: &mut IronRequest, err: IronError) -> IronResult<IronResponse> {
        let mut res = err.response;
        let inner_err = err.error;
        self.add_header(&mut res);

        Err(IronError {
            error: inner_err,
            response: res,
        })
    }
}

fn main() {
    let mut router = Router::new();

    router.get("/avatar/:email_md5", MainHandler, "email_md5");

    let mut chain = IronChain::new(router);
    chain.link_after(CustomErrorMsg);
    chain.link_after(AddXPoweredBy);

    chain.link(Write::<AvatarCache>::both(LruCache::new(102400)));

    Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS+CONNECT
//   FIXED A STINKER OF A BUG!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
    let mut i = 0;
    let mut x = 0;
    let mut request = String::new();

    let srch = needle.as_bytes();

    if srch.len() == 0
    {
        return request;
    }

    while buf[i] as char != '\0'
    {
        if buf[i] as char == srch[0] as char
        {
            while x < srch.len() && buf[i] as char  == srch[x] as char
            {
                i = i + 1;
                x = x + 1;
            }
            break;
        } else {
            i = i + 1;
        }
    }

    if x == srch.len()
    {
        //println!("match");
        let mut end = i;
        while buf[end] as char != byte as char && buf[end] as char != '\n'
        {
            end = end + 1;

        }

        for y in (i..end)
        {
            request.push(buf[y] as char);
        }
    }

    return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
    let mut current = 0;
    let mut buf = [0u8; CHUNK];

    while current < total
    {
        let bytes = outstream.read(&mut buf). unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent <= 0
            {
                break;
            }
            chunk = chunk + sent;
            current = current + chunk;
        }
    }
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
    loop {
        let mut buf = [0u8; CHUNK];

        let bytes = outstream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break; // please!!!
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk = chunk + sent;
        }
    }
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_options_request(mut instream: TcpStream)
{
    let allow = "GET,POST,HEAD,OPTIONS";
    let code: String = "HTTP/1.1 200 OK\r\n".to_string();
    let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

    let response = format!("{}{}", code, request);

    instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("xHEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

    outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);
    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    let mut buf = [0u8; CHUNK];
    let mut current = 0;

    while current < headers.length
    {
        let bytes = instream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = outstream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk += sent;
            current = current + chunk;
        }
    }

    let terminate = "\r\n\r\n";

    outstream.write(terminate.as_bytes()).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    if headers.length > 0
    {
        get_with_content_length(&instream, &outstream, headers.length);
    }
    else
    {
        get_with_no_content_length(&instream, &outstream);
    }
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
    let mut i = 0;
    let bytes = buf;
    let mut request: String = String::new();

    while bytes[i] as char != '\0'
    {
        request.push(bytes[i] as char);
        i += 1;
    }

    return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
    let content = substr(buf, "Content-Type: ", '\r' as u8);

    return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
    let hostname: String = substr(buf, "http://", '/' as u8);

    return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
    let request: String = substr(buf, "Content-Length: ", '\r' as u8);
    if ! request.is_empty()
    {
        return request.trim().parse().unwrap();
    }

    return 0;
}

struct Header {
    pub hostname: String,
    pub resource: String,
    pub content: String,
    pub length: usize,
    pub method: String,
}

impl Header {

pub fn new() -> Header
{
    let hostname = String::new();
    let resource = String::new();
    let content  = String::new();
    let method   = String::new();
    let length   = 0;

    let h = Header
        { hostname: hostname, resource: resource , content: content, length: length, method: method};

    return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{

    if headers.hostname.is_empty()
    {
        headers.hostname = req_hostname(buffer);
    }

    if headers.resource.is_empty()
    {
        headers.resource = req_resource(buffer);
    }

    if headers.content.is_empty()
    {
        headers.content = req_content(buffer);
    }

    if headers.length == 0
    {
        headers.length = req_length(buffer);
    }

    if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty()
    {
        return false;
    }

    return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
    let mut have_method = false;
    let mut byte = [0u8;1];
    let mut byte_count = 0;

    while ! have_method && byte_count < 16
    {
        instream.read(&mut byte).unwrap();
        if byte[0] as char != ' '
        {
            headers.method.push(byte[0] as char);
        }

        if byte[0] as char == ' '
        {
            have_method = true;
        }

        byte_count += 1;
    }

    if byte_count == 16 || headers.method.is_empty()
    {
        return;
    }

     loop
     {
	  let mut buffer = [0u8; REQUEST_LEN];
          let mut byte = [0u8; 1];
          let mut len = 0;

          while byte[0] as char != '\n'
          {
              let bytes = instream.read(&mut byte).unwrap();
              buffer[len] = byte[0];
              len += bytes;
          }

          buffer[len] = 0;

          if check_headers(buffer, headers) && len == 2
          {
              return;
          }
     }
}

fn proxy(stream: TcpStream) {
    let mut headers: Header = Header::new();
    request_headers(&stream, &mut headers);

    match headers.method.as_ref() {
            "GET" =>
            {
                http_get_request(stream, headers);
            }

            "POST" =>
            {
                http_post_request(stream, headers);
            }

            "HEAD" =>
            {
                http_head_request(stream, headers);
            }

            "OPTIONS" =>
            {
                http_options_request(stream);
            }

            _ =>
            {
                println!("REQUEST UNKNOWN");
            }
        }
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let host = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(host).unwrap();

    let pool = ThreadPool::new(threads);

    for stream in listener.incoming()
    {
        match stream
        {
            Ok(stream) =>
            {
                pool.execute(move || { proxy(stream); });
            }

            Err(_) =>
            {
                println!("NET error");
                1 << 7;
            }
        }
    }

    drop (listener);
}

fn main () {
    let threads = 128;
    let port: u16 = 9999;

    proxy_time(port, threads);
    println!("Blocking all badness");

}

<commit_msg>aye aye<commit_after>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS+CONNECT
//   FIXED A STINKER OF A BUG!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
    let mut i = 0;
    let mut x = 0;
    let mut request = String::new();

    let srch = needle.as_bytes();

    if srch.len() == 0
    {
        return request;
    }

    while buf[i] as char != '\0'
    {
        if buf[i] as char == srch[0] as char
        {
            while x < srch.len() && buf[i] as char  == srch[x] as char
            {
                i = i + 1;
                x = x + 1;
            }
            break;
        } else {
            i = i + 1;
        }
    }

    if x == srch.len()
    {
        //println!("match");
        let mut end = i;
        while buf[end] as char != byte as char && buf[end] as char != '\n'
        {
            end = end + 1;

        }

        for y in (i..end)
        {
            request.push(buf[y] as char);
        }
    }

    return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
    let mut current = 0;
    let mut buf = [0u8; CHUNK];

    while current < total
    {
        let bytes = outstream.read(&mut buf). unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent <= 0
            {
                break;
            }
            chunk = chunk + sent;
            current = current + chunk;
        }
    }
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
    loop {
        let mut buf = [0u8; CHUNK];

        let bytes = outstream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break; // please!!!
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk = chunk + sent;
        }
    }
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_options_request(mut instream: TcpStream)
{
    let allow = "GET,POST,HEAD,OPTIONS";
    let code: String = "HTTP/1.1 200 OK\r\n".to_string();
    let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

    let response = format!("{}{}", code, request);

    instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("xHEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

    outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);
    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    let mut buf = [0u8; CHUNK];
    let mut current = 0;

    while current < headers.length
    {
        let bytes = instream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = outstream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk += sent;
            current = current + chunk;
        }
    }

    let terminate = "\r\n\r\n";

    outstream.write(terminate.as_bytes()).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    if headers.length > 0
    {
        get_with_content_length(&instream, &outstream, headers.length);
    }
    else
    {
        get_with_no_content_length(&instream, &outstream);
    }
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
    let mut i = 0;
    let bytes = buf;
    let mut request: String = String::new();

    while bytes[i] as char != '\0'
    {
        request.push(bytes[i] as char);
        i += 1;
    }

    return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
    let content = substr(buf, "Content-Type: ", '\r' as u8);

    return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
    let hostname: String = substr(buf, "http://", '/' as u8);

    return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
    let request: String = substr(buf, "Content-Length: ", '\r' as u8);
    if ! request.is_empty()
    {
        return request.trim().parse().unwrap();
    }

    return 0;
}

struct Header {
    pub hostname: String,
    pub resource: String,
    pub content: String,
    pub length: usize,
    pub method: String,
}

impl Header {

pub fn new() -> Header
{
    let hostname = String::new();
    let resource = String::new();
    let content  = String::new();
    let method   = String::new();
    let length   = 0;

    let h = Header
        { hostname: hostname, resource: resource , content: content, length: length, method: method};

    return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{

    if headers.hostname.is_empty()
    {
        headers.hostname = req_hostname(buffer);
    }

    if headers.resource.is_empty()
    {
        headers.resource = req_resource(buffer);
    }

    if headers.content.is_empty()
    {
        headers.content = req_content(buffer);
    }

    if headers.length == 0
    {
        headers.length = req_length(buffer);
    }

    if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty()
    {
        return false;
    }

    return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
    let mut have_method = false;
    let mut byte = [0u8;1];
    let mut byte_count = 0;

	let longest_method = 8;

    while byte_count != longest_method
    {
        instream.read(&mut byte).unwrap();
		if byte[0] as char == ' ' && byte_count != 0
		{
			break;
		}

        if byte[0] as char != ' '
        {
            headers.method.push(byte[0] as char);

		    match headers.method.as_ref()
			{
				"GET" | "POST" | "HEAD" | "OPTIONS" =>
				{
					have_method = true;
				}

				_ =>
				{
					have_method = false;
				}
			}
        }

        byte_count += 1;
    }

    if ! have_method
    {
        return;
    }

     loop
     {
	  let mut buffer = [0u8; REQUEST_LEN];
          let mut byte = [0u8; 1];
          let mut len = 0;

          while byte[0] as char != '\n'
          {
              let bytes = instream.read(&mut byte).unwrap();
              buffer[len] = byte[0];
              len += bytes;
          }

          buffer[len] = 0;

          if check_headers(buffer, headers) && len == 2
          {
              return;
          }
     }
}

fn proxy(stream: TcpStream) {
    let mut headers: Header = Header::new();
    request_headers(&stream, &mut headers);

    match headers.method.as_ref() {
            "GET" =>
            {
                http_get_request(stream, headers);
            }

            "POST" =>
            {
                http_post_request(stream, headers);
            }

            "HEAD" =>
            {
                http_head_request(stream, headers);
            }

            "OPTIONS" =>
            {
                http_options_request(stream);
            }

            _ =>
            {
                println!("REQUEST UNKNOWN");
            }
        }
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let host = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(host).unwrap();

    let pool = ThreadPool::new(threads);

    for stream in listener.incoming()
    {
        match stream
        {
            Ok(stream) =>
            {
                pool.execute(move || { proxy(stream); });
            }

            Err(_) =>
            {
                println!("NET error");
                1 << 7;
            }
        }
    }

    drop (listener);
}

fn main () {
    let threads = 128;
    let port: u16 = 9999;

    proxy_time(port, threads);
    println!("Blocking all badness");

}

<|endoftext|>


<commit_before>use std::io;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

mod request;
mod turn;
mod region;
mod superregion;

use request::Request;
use turn::Turn;
use region::Region;
use superregion::SuperRegion;

fn main()
{
	std::env::set_var("RUST_BACKTRACE","1");
	let input = io::stdin();
	let input = BufReader::new(input);
	let input = input.lines();
	let input = input
		.map(Result::unwrap)
		.filter(|s|s.len()>0)
		.map(|s|s.parse::<Request>())
		.map(Result::unwrap);

	let mut name_you = String::new();
	let mut name_other = String::new();

	let mut sup_regions: HashMap<usize,SuperRegion> = HashMap::new();
	let mut regions: HashMap<usize,Region> = HashMap::new();

	let mut armies_left = 0;

	for req in input
	{
		use request::Request::*;
		match req
		{
			ListSuperRegions(sregions) =>
			{
				sup_regions.extend(sregions.iter().map(|sr|(sr.id,sr.clone())));
			},
			ListRegions(regs) =>
			{
				regions.extend(regs.iter().map(|r|(r.id,r.clone())));
			},
			ListNeighbours(relations) =>
			{
				for (id,neighbours) in relations
				{
					regions.get_mut(&id).unwrap().neighbours.extend(neighbours.iter());
					for n in neighbours
					{
						regions.get_mut(&n).unwrap().neighbours.push(id);
					}
				}
			},
			RequestStartingRegions(_avail) =>
			{
				println!("give me randomly");
			},
			SettingNameYou(name) => name_you = name,
			SettingNameOther(name) => name_other = name,
			SettingArmies(count) =>
			{
				armies_left = count;
			},
			UpdateMap(updates) =>
			{
				for u in updates
				{
					let mut reg = regions.get_mut(&u.0).unwrap();
					reg.player = u.1;
					reg.count = u.2;
				}
			},
			TurnOther(_turns) =>
			{
				//TODO: what the hell?
			},
			TurnPlace =>
			{
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.filter(|r|r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.any(|o|o.count*2 < r.count)
					).collect::<Vec<_>>();

				let mut v = Vec::new();
				if armies_left > regs.len()
				{
					let count = if regs.len() > 0
					{
						armies_left/regs.len()
					}
					else
					{
						1
					};
					for r in regs
					{
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: count,
							}
						);
						armies_left -= count;
					}
					v.push(
						Turn::Place
						{
							name: name_you.clone(),
							region: regions.values().max_by_key(|r|r.count).unwrap().id,
							count: armies_left,
						}
					);
				}
				else
				{
					for r in regs
					{
						if armies_left <= 0
						{
							break;
						}
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: 1,
							}
						);
						armies_left -= 1;
					}
				}
				let v = v.iter().map(|t|format!("{}",t)).collect::<Vec<_>>();
				println!("{}",v.join(","));
			},
			TurnArmies =>
			{
				let mut v = Vec::new();
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.map(|r|((r.id,r.count*2/3),r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.filter(|o|o.count*3 < r.count)
						.next()
						.unwrap().id))
					.collect::<Vec<_>>();
				for ((r,count),n) in regs
				{
					v.push(
						Turn::Turn
						{
							name: name_you.clone(),
							source: r,
							target: n,
							count: count,
						}
					);
				}
			},
		}
	}
}

<commit_msg>fix panics<commit_after>use std::io;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

mod request;
mod turn;
mod region;
mod superregion;

use request::Request;
use turn::Turn;
use region::Region;
use superregion::SuperRegion;

fn main()
{
	std::env::set_var("RUST_BACKTRACE","1");
	let input = io::stdin();
	let input = BufReader::new(input);
	let input = input.lines();
	let input = input
		.map(Result::unwrap)
		.filter(|s|s.len()>0)
		.map(|s|s.parse::<Request>())
		.map(Result::unwrap);

	let mut name_you = String::new();
	let mut name_other = String::new();

	let mut sup_regions: HashMap<usize,SuperRegion> = HashMap::new();
	let mut regions: HashMap<usize,Region> = HashMap::new();

	let mut armies_left = 0;

	for req in input
	{
		use request::Request::*;
		match req
		{
			ListSuperRegions(sregions) =>
			{
				sup_regions.extend(sregions.iter().map(|sr|(sr.id,sr.clone())));
			},
			ListRegions(regs) =>
			{
				regions.extend(regs.iter().map(|r|(r.id,r.clone())));
			},
			ListNeighbours(relations) =>
			{
				for (id,neighbours) in relations
				{
					regions.get_mut(&id).unwrap().neighbours.extend(neighbours.iter());
					for n in neighbours
					{
						regions.get_mut(&n).unwrap().neighbours.push(id);
					}
				}
			},
			RequestStartingRegions(_avail) =>
			{
				println!("give me randomly");
			},
			SettingNameYou(name) => name_you = name,
			SettingNameOther(name) => name_other = name,
			SettingArmies(count) =>
			{
				armies_left = count;
			},
			UpdateMap(updates) =>
			{
				for u in updates
				{
					let mut reg = regions.get_mut(&u.0).unwrap();
					reg.player = u.1;
					reg.count = u.2;
				}
			},
			TurnOther(_turns) =>
			{
				//TODO: what the hell?
			},
			TurnPlace =>
			{
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.filter(|r|r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.any(|o|o.count*2 < r.count)
					).collect::<Vec<_>>();

				let mut v = Vec::new();
				if armies_left > regs.len()
				{
					let count = if regs.len() > 0
					{
						armies_left/regs.len()
					}
					else
					{
						1
					};
					for r in regs
					{
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: count,
							}
						);
						armies_left -= count;
					}
					v.push(
						Turn::Place
						{
							name: name_you.clone(),
							region: regions.values().max_by_key(|r|r.count).unwrap().id,
							count: armies_left,
						}
					);
				}
				else
				{
					for r in regs
					{
						if armies_left <= 0
						{
							break;
						}
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: 1,
							}
						);
						armies_left -= 1;
					}
				}
				let v = v.iter().map(|t|format!("{}",t)).collect::<Vec<_>>();
				println!("{}",v.join(","));
			},
			TurnArmies =>
			{
				let mut v = Vec::new();
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.filter_map(|r|
					{
						let x =r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.filter(|o|o.count*3 < r.count)
						.next()
						.map(|o|o.id);
						if let Some(x) = x
						{
							Some(((r.id,r.count*2/3),x))
						}
						else
						{
							None
						}
					})
					.collect::<Vec<_>>();
				for ((r,count),n) in regs
				{
					v.push(
						Turn::Turn
						{
							name: name_you.clone(),
							source: r,
							target: n,
							count: count,
						}
					);
				}
			},
		}
	}
}

<|endoftext|>