<commit_before>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection
    NoIntersection
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Origin {
    pub fn new(x: c_int, y: c_int) -> Self {
        Origin { x, y }
    }
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

impl Into<Area> for Origin {
    fn into(self) -> Area {
        Area::new(self, Size::default())
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Size {
    pub fn new(width: c_int, height: c_int) -> Self {
        Size { width, height }
    }
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

impl Into<Area> for Size {
    fn into(self) -> Area {
        Area::new(Origin::default(), self)
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Makes a new `Area` with width and height set to the values in the given
    /// `Size`.
    pub fn with_size(self, size: Size) -> Self {
        Area(wlr_box { width: size.width,
                       height: size.height,
                       ..self.0 })
    }

    /// Makes a new `Area` with x and y set to the value in the given `Origin`.
    pub fn with_origin(self, origin: Origin) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       ..self.0 })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty = wlr_box_intersection(&self.0, &other_box.0, &mut res.0);
            if is_empty {
                IntersectionResult::NoIntersection
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self,
                     transform: wl_output_transform,
                     width: c_int,
                     height: c_int)
                     -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, width, height, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<commit_msg>Area -> {Size,Origin} Into impl<commit_after>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection
    NoIntersection
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Origin {
    pub fn new(x: c_int, y: c_int) -> Self {
        Origin { x, y }
    }
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

impl Into<Area> for Origin {
    fn into(self) -> Area {
        Area::new(self, Size::default())
    }
}

impl Into<Origin> for Area {
    fn into(self) -> Origin {
        Origin { x: self.0.x, y: self.0.y }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Size {
    pub fn new(width: c_int, height: c_int) -> Self {
        Size { width, height }
    }
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

impl Into<Area> for Size {
    fn into(self) -> Area {
        Area::new(Origin::default(), self)
    }
}

impl Into<Size> for Area {
    fn into(self) -> Size {
        Size { width: self.0.width, height: self.0.height }
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Makes a new `Area` with width and height set to the values in the given
    /// `Size`.
    pub fn with_size(self, size: Size) -> Self {
        Area(wlr_box { width: size.width,
                       height: size.height,
                       ..self.0 })
    }

    /// Makes a new `Area` with x and y set to the value in the given `Origin`.
    pub fn with_origin(self, origin: Origin) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       ..self.0 })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty = wlr_box_intersection(&self.0, &other_box.0, &mut res.0);
            if is_empty {
                IntersectionResult::NoIntersection
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self,
                     transform: wl_output_transform,
                     width: c_int,
                     height: c_int)
                     -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, width, height, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<|endoftext|>


<commit_before>#![feature(custom_derive, plugin, custom_attribute, test)]
#![plugin(diesel_codegen)]
#[macro_use]
extern crate diesel;
extern crate test;

mod schema;

use self::test::Bencher;
use self::schema::*;
use diesel::*;

#[bench]
fn bench_selecting_0_rows_with_trivial_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);

    b.iter(|| {
        users::table.load(&conn).unwrap().collect::<Vec<User>>();
    })
}

#[bench]
fn bench_selecting_10k_rows_with_trivial_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);
    let data: Vec<_> = (0..10_000).map(|i| {
        NewUser::new(&format!("User {}", i), None)
    }).collect();
    insert(&data).into(users::table).execute(&conn).unwrap();

    b.iter(|| {
        users::table.load(&conn).unwrap().collect::<Vec<User>>()
    })
}

#[bench]
fn bench_selecting_0_rows_with_medium_complex_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);
    setup_posts_table(&conn);

    b.iter(|| {
        use schema::users::dsl::*;
        let target = users.left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .order(name.desc());
        target.load(&conn).unwrap().collect::<Vec<(User, Option<Post>)>>()
    })
}

#[bench]
fn bench_selecting_10k_rows_with_medium_complex_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);
    setup_posts_table(&conn);

    let data: Vec<_> = (0..10_000).map(|i| {
        let hair_color = if i % 2 == 0 { "black" } else { "brown" };
        NewUser::new(&format!("User {}", i), Some(hair_color))
    }).collect();
    insert(&data).into(users::table).execute(&conn).unwrap();

    b.iter(|| {
        use schema::users::dsl::*;
        let target = users.left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .order(name.desc());
        target.load(&conn).unwrap().collect::<Vec<(User, Option<Post>)>>()
    })
}
<commit_msg>Our benchmarks need to declare `dotenv_macros` to compile<commit_after>#![feature(custom_derive, plugin, custom_attribute, test)]
#![plugin(diesel_codegen, dotenv_macros)]
#[macro_use]
extern crate diesel;
extern crate test;

mod schema;

use self::test::Bencher;
use self::schema::*;
use diesel::*;

#[bench]
fn bench_selecting_0_rows_with_trivial_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);

    b.iter(|| {
        users::table.load(&conn).unwrap().collect::<Vec<User>>();
    })
}

#[bench]
fn bench_selecting_10k_rows_with_trivial_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);
    let data: Vec<_> = (0..10_000).map(|i| {
        NewUser::new(&format!("User {}", i), None)
    }).collect();
    insert(&data).into(users::table).execute(&conn).unwrap();

    b.iter(|| {
        users::table.load(&conn).unwrap().collect::<Vec<User>>()
    })
}

#[bench]
fn bench_selecting_0_rows_with_medium_complex_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);
    setup_posts_table(&conn);

    b.iter(|| {
        use schema::users::dsl::*;
        let target = users.left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .order(name.desc());
        target.load(&conn).unwrap().collect::<Vec<(User, Option<Post>)>>()
    })
}

#[bench]
fn bench_selecting_10k_rows_with_medium_complex_query(b: &mut Bencher) {
    let conn = connection();
    setup_users_table(&conn);
    setup_posts_table(&conn);

    let data: Vec<_> = (0..10_000).map(|i| {
        let hair_color = if i % 2 == 0 { "black" } else { "brown" };
        NewUser::new(&format!("User {}", i), Some(hair_color))
    }).collect();
    insert(&data).into(users::table).execute(&conn).unwrap();

    b.iter(|| {
        use schema::users::dsl::*;
        let target = users.left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .order(name.desc());
        target.load(&conn).unwrap().collect::<Vec<(User, Option<Post>)>>()
    })
}
<|endoftext|>


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

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

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

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

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Empty
}

enum Opcode {
    TextOp = 0x1,
    BinaryOp = 0x2
}

struct Message {
    payload: Payload,
    opcode: Opcode
 }

impl Message {

    fn new (msg: &String) -> Message {

        let (payload, opcode) = match msg {
            String => (Payload::Text(msg.to_string()), Opcode::TextOp)
        };

        return Message{payload: payload, opcode: opcode};
    }

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

        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Empty => unimplemented!()
        };

        let length = msg.len() as u8;

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

        stream.write_u8(0b1000_0000 | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();

    }
}

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

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

    return result;
}

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

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

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

    }

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

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

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

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

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

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

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

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

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

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

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

    let mut sha = Sha1::new();

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

    return out.to_base64(STANDARD);
}

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

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

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

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

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

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             headers: Vec<ClientHeader>) {
    let string_msg = "this is a message".to_string();
    let msg = box Message::new(&string_msg);
    msg.send(stream, headers);
}

fn main () {

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

    let addr = "127.0.0.1:8099";

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

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

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

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

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

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

        }

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

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

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

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

        println!("Done handling acceptor");
    }

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

    drop(acceptor);
}
<commit_msg>explain magic number<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

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

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

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

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Empty
}

enum Opcode {
    TextOp = 0x1,
    BinaryOp = 0x2
}

struct Message {
    payload: Payload,
    opcode: Opcode
 }

impl Message {

    fn new (msg: &String) -> Message {

        let (payload, opcode) = match msg {
            String => (Payload::Text(msg.to_string()), Opcode::TextOp)
        };

        return Message{payload: payload, opcode: opcode};
    }

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

        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Empty => unimplemented!()
        };

        let length = msg.len() as u8;

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

        stream.write_u8(0b1000_0000 | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();

    }
}

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

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

    return result;
}

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

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

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

    }

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

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

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

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

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

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

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

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

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

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

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

    let mut sha = Sha1::new();

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

    return out.to_base64(STANDARD);
}

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

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

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

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

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

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             headers: Vec<ClientHeader>) {
    let string_msg = "this is a message".to_string();
    let msg = box Message::new(&string_msg);
    msg.send(stream, headers);
}

fn main () {

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

    let addr = "127.0.0.1:8099";

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

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

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

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

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

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

        }

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

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

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

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

        println!("Done handling acceptor");
    }

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

    drop(acceptor);
}
<|endoftext|>


<commit_before>/*!

bbb compression model

# Links

* http://mattmahoney.net/dc/bbb.cpp

*/

use std::io;
use compress::entropy::ari;
use super::Symbol;

/// Symbol encoding context //TODO
pub type Context = ();

const FIXED_BASE    : u32 = 8;
const LOG_LIMIT     : usize = 10;
const LOG_DEFAULT   : u32 = 1<<FIXED_BASE;

/// Coding model for BWT-DC output
pub struct Model {
    next_prob: ari::apm::Bit,
    avg_log: [u32; 0x100],   //fixed-point
    prob: [[ari::apm::Bit; 24]; LOG_LIMIT],
}

impl Model {
    /// Create a new model
    pub fn new() -> Model {
        Model {
            next_prob: ari::apm::Bit::new_equal(),
            avg_log: [LOG_DEFAULT; 0x100],
            prob: [[ari::apm::Bit::new_equal(); 24]; LOG_LIMIT],
        }
    }

    fn update(&mut self, bit: u8) {
        //TODO
    }

    fn predict(&self) -> ari::apm::Bit {
        if self.next_prob.predict() {
            self.next_prob.clone()
        }else {
            // weird hack by MM, TODO: investigate
            let flat = self.next_prob.to_flat() + 1;
            ari::apm::Bit::from_flat(flat)
        }
    }
}

impl super::Model<Symbol, Context> for Model {
    fn reset(&mut self) {
        for log in self.avg_log.iter_mut() {
            *log = LOG_DEFAULT;
        }
        for log in self.prob.iter_mut() {
            for bit in log.iter_mut() {
                *bit = ari::apm::Bit::new_equal();
            }
        }
    }

    fn encode<W: io::Write>(&mut self, sym: Symbol, _ctx: &Context,
              eh: &mut ari::Encoder<W>) -> io::Result<()> {
        for i in (0..8).rev() {
            let bit = (sym >> i) & 1;
            try!(eh.encode(bit != 0, &self.predict()));
            self.update(bit);
        }
        Ok(())
    }

    fn decode<R: io::Read>(&mut self, _ctx: &Context, dh: &mut ari::Decoder<R>)
              -> io::Result<Symbol> {
        let mut sym = 0 as Symbol;
        for i in (0..8).rev() {
            let bit_b = try!(dh.decode( &self.predict() ));
            let bit = if bit_b {1} else {0};
            self.update(bit);
            sym |= bit << i;
        }
        Ok(sym)
    }
}
<commit_msg>bbb - added the state table and cleaned up the old model<commit_after>/*!

bbb compression model

# Links

* http://mattmahoney.net/dc/bbb.cpp

*/

use std::io;
use compress::entropy::ari;
use super::{Symbol, SymContext};

/// State table:
///   nex(state, 0) = next state if bit y is 0, 0 <= state < 256
///   nex(state, 1) = next state if bit y is 1
///   nex(state, 2) = number of zeros in bit history represented by state
///   nex(state, 3) = number of ones represented
///
/// States represent a bit history within some context.
/// State 0 is the starting state (no bits seen).
/// States 1-30 represent all possible sequences of 1-4 bits.
/// States 31-252 represent a pair of counts, (n0,n1), the number
///   of 0 and 1 bits respectively.  If n0+n1 < 16 then there are
///   two states for each pair, depending on if a 0 or 1 was the last
///   bit seen.
/// If n0 and n1 are too large, then there is no state to represent this
/// pair, so another state with about the same ratio of n0/n1 is substituted.
/// Also, when a bit is observed and the count of the opposite bit is large,
/// then part of this count is discarded to favor newer data over old.
const STATE_TABLE: [[u8; 4]; 0x100] = [
    [  1,  2, 0, 0], [  3,  5, 1, 0], [  4,  6, 0, 1], [  7, 10, 2, 0], // 0-3
    [  8, 12, 1, 1], [  9, 13, 1, 1], [ 11, 14, 0, 2], [ 15, 19, 3, 0], // 4-7
    [ 16, 23, 2, 1], [ 17, 24, 2, 1], [ 18, 25, 2, 1], [ 20, 27, 1, 2], // 8-11
    [ 21, 28, 1, 2], [ 22, 29, 1, 2], [ 26, 30, 0, 3], [ 31, 33, 4, 0], // 12-15
    [ 32, 35, 3, 1], [ 32, 35, 3, 1], [ 32, 35, 3, 1], [ 32, 35, 3, 1], // 16-19
    [ 34, 37, 2, 2], [ 34, 37, 2, 2], [ 34, 37, 2, 2], [ 34, 37, 2, 2], // 20-23
    [ 34, 37, 2, 2], [ 34, 37, 2, 2], [ 36, 39, 1, 3], [ 36, 39, 1, 3], // 24-27
    [ 36, 39, 1, 3], [ 36, 39, 1, 3], [ 38, 40, 0, 4], [ 41, 43, 5, 0], // 28-31
    [ 42, 45, 4, 1], [ 42, 45, 4, 1], [ 44, 47, 3, 2], [ 44, 47, 3, 2], // 32-35
    [ 46, 49, 2, 3], [ 46, 49, 2, 3], [ 48, 51, 1, 4], [ 48, 51, 1, 4], // 36-39
    [ 50, 52, 0, 5], [ 53, 43, 6, 0], [ 54, 57, 5, 1], [ 54, 57, 5, 1], // 40-43
    [ 56, 59, 4, 2], [ 56, 59, 4, 2], [ 58, 61, 3, 3], [ 58, 61, 3, 3], // 44-47
    [ 60, 63, 2, 4], [ 60, 63, 2, 4], [ 62, 65, 1, 5], [ 62, 65, 1, 5], // 48-51
    [ 50, 66, 0, 6], [ 67, 55, 7, 0], [ 68, 57, 6, 1], [ 68, 57, 6, 1], // 52-55
    [ 70, 73, 5, 2], [ 70, 73, 5, 2], [ 72, 75, 4, 3], [ 72, 75, 4, 3], // 56-59
    [ 74, 77, 3, 4], [ 74, 77, 3, 4], [ 76, 79, 2, 5], [ 76, 79, 2, 5], // 60-63
    [ 62, 81, 1, 6], [ 62, 81, 1, 6], [ 64, 82, 0, 7], [ 83, 69, 8, 0], // 64-67
    [ 84, 71, 7, 1], [ 84, 71, 7, 1], [ 86, 73, 6, 2], [ 86, 73, 6, 2], // 68-71
    [ 44, 59, 5, 3], [ 44, 59, 5, 3], [ 58, 61, 4, 4], [ 58, 61, 4, 4], // 72-75
    [ 60, 49, 3, 5], [ 60, 49, 3, 5], [ 76, 89, 2, 6], [ 76, 89, 2, 6], // 76-79
    [ 78, 91, 1, 7], [ 78, 91, 1, 7], [ 80, 92, 0, 8], [ 93, 69, 9, 0], // 80-83
    [ 94, 87, 8, 1], [ 94, 87, 8, 1], [ 96, 45, 7, 2], [ 96, 45, 7, 2], // 84-87
    [ 48, 99, 2, 7], [ 48, 99, 2, 7], [ 88,101, 1, 8], [ 88,101, 1, 8], // 88-91
    [ 80,102, 0, 9], [103, 69,10, 0], [104, 87, 9, 1], [104, 87, 9, 1], // 92-95
    [106, 57, 8, 2], [106, 57, 8, 2], [ 62,109, 2, 8], [ 62,109, 2, 8], // 96-99
    [ 88,111, 1, 9], [ 88,111, 1, 9], [ 80,112, 0,10], [113, 85,11, 0], // 100-103
    [114, 87,10, 1], [114, 87,10, 1], [116, 57, 9, 2], [116, 57, 9, 2], // 104-107
    [ 62,119, 2, 9], [ 62,119, 2, 9], [ 88,121, 1,10], [ 88,121, 1,10], // 108-111
    [ 90,122, 0,11], [123, 85,12, 0], [124, 97,11, 1], [124, 97,11, 1], // 112-115
    [126, 57,10, 2], [126, 57,10, 2], [ 62,129, 2,10], [ 62,129, 2,10], // 116-119
    [ 98,131, 1,11], [ 98,131, 1,11], [ 90,132, 0,12], [133, 85,13, 0], // 120-123
    [134, 97,12, 1], [134, 97,12, 1], [136, 57,11, 2], [136, 57,11, 2], // 124-127
    [ 62,139, 2,11], [ 62,139, 2,11], [ 98,141, 1,12], [ 98,141, 1,12], // 128-131
    [ 90,142, 0,13], [143, 95,14, 0], [144, 97,13, 1], [144, 97,13, 1], // 132-135
    [ 68, 57,12, 2], [ 68, 57,12, 2], [ 62, 81, 2,12], [ 62, 81, 2,12], // 136-139
    [ 98,147, 1,13], [ 98,147, 1,13], [100,148, 0,14], [149, 95,15, 0], // 140-143
    [150,107,14, 1], [150,107,14, 1], [108,151, 1,14], [108,151, 1,14], // 144-147
    [100,152, 0,15], [153, 95,16, 0], [154,107,15, 1], [108,155, 1,15], // 148-151
    [100,156, 0,16], [157, 95,17, 0], [158,107,16, 1], [108,159, 1,16], // 152-155
    [100,160, 0,17], [161,105,18, 0], [162,107,17, 1], [108,163, 1,17], // 156-159
    [110,164, 0,18], [165,105,19, 0], [166,117,18, 1], [118,167, 1,18], // 160-163
    [110,168, 0,19], [169,105,20, 0], [170,117,19, 1], [118,171, 1,19], // 164-167
    [110,172, 0,20], [173,105,21, 0], [174,117,20, 1], [118,175, 1,20], // 168-171
    [110,176, 0,21], [177,105,22, 0], [178,117,21, 1], [118,179, 1,21], // 172-175
    [110,180, 0,22], [181,115,23, 0], [182,117,22, 1], [118,183, 1,22], // 176-179
    [120,184, 0,23], [185,115,24, 0], [186,127,23, 1], [128,187, 1,23], // 180-183
    [120,188, 0,24], [189,115,25, 0], [190,127,24, 1], [128,191, 1,24], // 184-187
    [120,192, 0,25], [193,115,26, 0], [194,127,25, 1], [128,195, 1,25], // 188-191
    [120,196, 0,26], [197,115,27, 0], [198,127,26, 1], [128,199, 1,26], // 192-195
    [120,200, 0,27], [201,115,28, 0], [202,127,27, 1], [128,203, 1,27], // 196-199
    [120,204, 0,28], [205,115,29, 0], [206,127,28, 1], [128,207, 1,28], // 200-203
    [120,208, 0,29], [209,125,30, 0], [210,127,29, 1], [128,211, 1,29], // 204-207
    [130,212, 0,30], [213,125,31, 0], [214,137,30, 1], [138,215, 1,30], // 208-211
    [130,216, 0,31], [217,125,32, 0], [218,137,31, 1], [138,219, 1,31], // 212-215
    [130,220, 0,32], [221,125,33, 0], [222,137,32, 1], [138,223, 1,32], // 216-219
    [130,224, 0,33], [225,125,34, 0], [226,137,33, 1], [138,227, 1,33], // 220-223
    [130,228, 0,34], [229,125,35, 0], [230,137,34, 1], [138,231, 1,34], // 224-227
    [130,232, 0,35], [233,125,36, 0], [234,137,35, 1], [138,235, 1,35], // 228-231
    [130,236, 0,36], [237,125,37, 0], [238,137,36, 1], [138,239, 1,36], // 232-235
    [130,240, 0,37], [241,125,38, 0], [242,137,37, 1], [138,243, 1,37], // 236-239
    [130,244, 0,38], [245,135,39, 0], [246,137,38, 1], [138,247, 1,38], // 240-243
    [140,248, 0,39], [249,135,40, 0], [250, 69,39, 1], [ 80,251, 1,39], // 244-247
    [140,252, 0,40], [249,135,41, 0], [250, 69,40, 1], [ 80,251, 1,40], // 248-251
    [140,252, 0,41], [  0,  0, 0, 0], [  0,  0, 0, 0], [  0,  0, 0, 0], // 253-255 are reserved
];

/// Coding model for BWT-DC output
pub struct Model {
    next_prob: ari::apm::Bit,
}

impl Model {
    /// Create a new model
    pub fn new() -> Model {
        Model {
            next_prob: ari::apm::Bit::new_equal(),
        }
    }

    fn update(&mut self, bit: u8, reset: bool) {
        //TODO
    }

    fn predict(&self) -> ari::apm::Bit {
        if self.next_prob.predict() {
            self.next_prob.clone()
        }else {
            // weird hack by MM, TODO: investigate
            let flat = self.next_prob.to_flat() + 1;
            ari::apm::Bit::from_flat(flat)
        }
    }
}

impl super::Model<Symbol, SymContext> for Model {
    fn reset(&mut self) {
        //TODO
    }

    fn encode<W: io::Write>(&mut self, sym: Symbol, _ctx: &SymContext,
              eh: &mut ari::Encoder<W>) -> io::Result<()> {
        for i in (0..8).rev() {
            let bit = (sym >> i) & 1;
            try!(eh.encode(bit != 0, &self.predict()));
            self.update(bit, i == 0);
        }
        Ok(())
    }

    fn decode<R: io::Read>(&mut self, _ctx: &SymContext, dh: &mut ari::Decoder<R>)
              -> io::Result<Symbol> {
        let mut sym = 0 as Symbol;
        for i in (0..8).rev() {
            let bit_b = try!(dh.decode( &self.predict() ));
            let bit = if bit_b {1} else {0};
            self.update(bit, i == 0);
            sym |= bit << i;
        }
        Ok(sym)
    }
}
<|endoftext|>


<commit_before>pub mod ffi;
pub mod status;

pub use self::status::Status;

use std::result;
use std::mem;

use libc::c_long;

macro_rules! getter {
   ( $field:ident, $restype:ident ) => {
      pub fn $field(&self) -> Option<$restype> {
         let raw = unsafe { (*self.raw).$field };

         if raw.is_null() {
            None
         } else {
            Some(
               $restype::new(raw)
            )
         }
      }
   };
}

struct Wrapper<R> {
   pub raw: *mut R,
}

impl<R> Wrapper<R> {
   pub fn new(raw: *mut R) -> Self {
      Wrapper::<R> {
         raw: raw
      }
   }
}

pub type Connection = Wrapper<ffi::ngx_connection_t>;

impl Connection {
   getter!(log, Log);
}

pub type Log = Wrapper<ffi::ngx_log_t>;

pub type HttpRequest = Wrapper<ffi::ngx_http_request_t>;

impl HttpRequest {
   getter!(connection, Connection);
   getter!(pool, Pool);

   pub fn headers_out(&self) -> HttpHeadersOut {
      let raw: *mut ffi::ngx_http_headers_out_t = unsafe { &mut (*self.raw).headers_out };

      HttpHeadersOut::new(raw)
   }

   pub fn http_send_header(&self) -> Status {
      let rc = unsafe { ffi::ngx_http_send_header(self.raw) };
      Status::new(rc)
   }
}

pub type HttpHeadersOut = Wrapper<ffi::ngx_http_headers_out_t>;

impl HttpHeadersOut {
   pub fn set_status(&mut self, status: ffi::ngx_uint_t) {
      unsafe {
         (*self.raw).status = status;
      };
   }

   pub fn set_content_length_n(&mut self, content_length_n: ffi::off_t) {
      unsafe {
         (*self.raw).content_length_n = content_length_n;
      };
   }
}

pub type Pool = Wrapper<ffi::ngx_pool_t>;

impl Pool {
   #[inline]
   pub fn raw_palloc<T>(&self) -> *mut T {
      unsafe {
         ffi::ngx_palloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      }
   }

   #[inline]
   pub fn raw_pnalloc<T>(&self) -> *mut T {
      unsafe {
         ffi::ngx_pnalloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      }
   }

   #[inline]
   pub fn raw_pcalloc<T>(&self) -> *mut T {
      unsafe {
         ffi::ngx_pcalloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      }
   }

}
<commit_msg>Wrapper for ngx_buf_t with allocation.<commit_after>pub mod ffi;
pub mod status;

pub use self::status::Status;

use std::result;
use std::mem;

use libc::c_long;

macro_rules! getter {
   ( $field:ident, $restype:ident ) => {
      pub fn $field(&self) -> Option<$restype> {
         let raw = unsafe { (*self.raw).$field };

         if raw.is_null() {
            None
         } else {
            Some(
               $restype::new(raw)
            )
         }
      }
   };
}

struct Wrapper<R> {
   pub raw: *mut R,
}

impl<R> Wrapper<R> {
   pub fn new(raw: *mut R) -> Self {
      Wrapper::<R> {
         raw: raw
      }
   }
}

pub type Connection = Wrapper<ffi::ngx_connection_t>;

impl Connection {
   getter!(log, Log);
}

pub type Log = Wrapper<ffi::ngx_log_t>;

pub type HttpRequest = Wrapper<ffi::ngx_http_request_t>;

impl HttpRequest {
   getter!(connection, Connection);
   getter!(pool, Pool);

   pub fn headers_out(&self) -> HttpHeadersOut {
      let raw: *mut ffi::ngx_http_headers_out_t = unsafe { &mut (*self.raw).headers_out };

      HttpHeadersOut::new(raw)
   }

   pub fn http_send_header(&self) -> Status {
      let rc = unsafe { ffi::ngx_http_send_header(self.raw) };
      Status::new(rc)
   }
}

pub type HttpHeadersOut = Wrapper<ffi::ngx_http_headers_out_t>;

impl HttpHeadersOut {
   pub fn set_status(&mut self, status: ffi::ngx_uint_t) {
      unsafe {
         (*self.raw).status = status;
      };
   }

   pub fn set_content_length_n(&mut self, content_length_n: ffi::off_t) {
      unsafe {
         (*self.raw).content_length_n = content_length_n;
      };
   }
}

pub type Pool = Wrapper<ffi::ngx_pool_t>;

impl Pool {
   pub fn alloc_buf(&self) -> Option<Buf> {
      match self.raw_palloc::<ffi::ngx_buf_t>() {
         None => { None }
         Some(raw) => {
            Some(
               Buf::new(raw)
            )
         }
      }
   }

   pub fn nalloc_buf(&self) -> Option<Buf> {
      match self.raw_pnalloc::<ffi::ngx_buf_t>() {
         None => { None }
         Some(raw) => {
            Some(
               Buf::new(raw)
            )
         }
      }
   }

   pub fn calloc_buf(&self) -> Option<Buf> {
      match self.raw_pcalloc::<ffi::ngx_buf_t>() {
         None => { None }
         Some(raw) => {
            Some(
               Buf::new(raw)
            )
         }
      }
   }

   #[inline]
   pub fn raw_palloc<T>(&self) -> Option<*mut T> {
      let raw = unsafe {
         ffi::ngx_palloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      };

      if raw.is_null() {
         None
      } else {
         Some(raw)
      }
   }

   #[inline]
   pub fn raw_pnalloc<T>(&self) -> Option<*mut T> {
      let raw = unsafe {
         ffi::ngx_pnalloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      };

      if raw.is_null() {
         None
      } else {
         Some(raw)
      }
   }

   #[inline]
   pub fn raw_pcalloc<T>(&self) -> Option<*mut T> {
      let raw = unsafe {
         ffi::ngx_pcalloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      };

      if raw.is_null() {
         None
      } else {
         Some(raw)
      }
   }

}

pub type Buf = Wrapper<ffi::ngx_buf_t>;
<|endoftext|>


<commit_before>#![crate_name = "uu_nice"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alex Lyon <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use libc::{c_char, c_int, execvp};
use std::ffi::CString;
use std::io::Error;

const NAME: &str = "nice";
const VERSION: &str = env!("CARGO_PKG_VERSION");

// XXX: PRIO_PROCESS is 0 on at least FreeBSD and Linux.  Don't know about Mac OS X.
const PRIO_PROCESS: c_int = 0;

extern "C" {
    fn getpriority(which: c_int, who: c_int) -> c_int;
    fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int;
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        "n",
        "adjustment",
        "add N to the niceness (default is 10)",
        "N",
    );
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(err) => {
            show_error!("{}", err);
            return 125;
        }
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") {
        let msg = format!(
            "{0} {1}

Usage:
  {0} [OPTIONS] [COMMAND [ARGS]]

Run COMMAND with an adjusted niceness, which affects process scheduling.
With no COMMAND, print the current niceness.  Niceness values range from at
least -20 (most favorable to the process) to 19 (least favorable to the
process).",
            NAME, VERSION
        );

        print!("{}", opts.usage(&msg));
        return 0;
    }

    let mut niceness = unsafe { getpriority(PRIO_PROCESS, 0) };
    if Error::last_os_error().raw_os_error().unwrap() != 0 {
        show_error!("{}", Error::last_os_error());
        return 125;
    }

    let adjustment = match matches.opt_str("adjustment") {
        Some(nstr) => {
            if matches.free.is_empty() {
                show_error!(
                    "A command must be given with an adjustment.
                                Try \"{} --help\" for more information.",
                    args[0]
                );
                return 125;
            }
            match nstr.parse() {
                Ok(num) => num,
                Err(e) => {
                    show_error!("\"{}\" is not a valid number: {}", nstr, e);
                    return 125;
                }
            }
        }
        None => {
            if matches.free.is_empty() {
                println!("{}", niceness);
                return 0;
            }
            10 as c_int
        }
    };

    niceness += adjustment;
    unsafe {
        setpriority(PRIO_PROCESS, 0, niceness);
    }
    if Error::last_os_error().raw_os_error().unwrap() != 0 {
        show_warning!("{}", Error::last_os_error());
    }

    let cstrs: Vec<CString> = matches
        .free
        .iter()
        .map(|x| CString::new(x.as_bytes()).unwrap())
        .collect();
    let mut args: Vec<*const c_char> = cstrs.iter().map(|s| s.as_ptr()).collect();
    args.push(0 as *const c_char);
    unsafe {
        execvp(args[0], args.as_mut_ptr());
    }

    show_error!("{}", Error::last_os_error());
    if Error::last_os_error().raw_os_error().unwrap() as c_int == libc::ENOENT {
        127
    } else {
        126
    }
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (zero_ptr)<commit_after>#![crate_name = "uu_nice"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alex Lyon <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use libc::{c_char, c_int, execvp};
use std::ffi::CString;
use std::io::Error;

const NAME: &str = "nice";
const VERSION: &str = env!("CARGO_PKG_VERSION");

// XXX: PRIO_PROCESS is 0 on at least FreeBSD and Linux.  Don't know about Mac OS X.
const PRIO_PROCESS: c_int = 0;

extern "C" {
    fn getpriority(which: c_int, who: c_int) -> c_int;
    fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int;
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        "n",
        "adjustment",
        "add N to the niceness (default is 10)",
        "N",
    );
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(err) => {
            show_error!("{}", err);
            return 125;
        }
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") {
        let msg = format!(
            "{0} {1}

Usage:
  {0} [OPTIONS] [COMMAND [ARGS]]

Run COMMAND with an adjusted niceness, which affects process scheduling.
With no COMMAND, print the current niceness.  Niceness values range from at
least -20 (most favorable to the process) to 19 (least favorable to the
process).",
            NAME, VERSION
        );

        print!("{}", opts.usage(&msg));
        return 0;
    }

    let mut niceness = unsafe { getpriority(PRIO_PROCESS, 0) };
    if Error::last_os_error().raw_os_error().unwrap() != 0 {
        show_error!("{}", Error::last_os_error());
        return 125;
    }

    let adjustment = match matches.opt_str("adjustment") {
        Some(nstr) => {
            if matches.free.is_empty() {
                show_error!(
                    "A command must be given with an adjustment.
                                Try \"{} --help\" for more information.",
                    args[0]
                );
                return 125;
            }
            match nstr.parse() {
                Ok(num) => num,
                Err(e) => {
                    show_error!("\"{}\" is not a valid number: {}", nstr, e);
                    return 125;
                }
            }
        }
        None => {
            if matches.free.is_empty() {
                println!("{}", niceness);
                return 0;
            }
            10 as c_int
        }
    };

    niceness += adjustment;
    unsafe {
        setpriority(PRIO_PROCESS, 0, niceness);
    }
    if Error::last_os_error().raw_os_error().unwrap() != 0 {
        show_warning!("{}", Error::last_os_error());
    }

    let cstrs: Vec<CString> = matches
        .free
        .iter()
        .map(|x| CString::new(x.as_bytes()).unwrap())
        .collect();
    let mut args: Vec<*const c_char> = cstrs.iter().map(|s| s.as_ptr()).collect();
    args.push(std::ptr::null::<c_char>());
    unsafe {
        execvp(args[0], args.as_mut_ptr());
    }

    show_error!("{}", Error::last_os_error());
    if Error::last_os_error().raw_os_error().unwrap() as c_int == libc::ENOENT {
        127
    } else {
        126
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.

/// Calculates the offset of the specified field from the start of the struct.
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
///
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
///
/// ## Examples
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
/// }
/// ```
#[macro_export]
#[cfg(memoffset_maybe_uninit)]
macro_rules! offset_of {
    ($parent:tt, $field:tt) => {{
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        let $parent { $field: _, .. };

        // Create an instance of the container and calculate the offset to its field.
        // Here we're using an uninitialized instance of $parent.
        // Since we're not using its field, there's no UB caused by reading uninitialized memory.
        // There *IS*, though, UB caused by creating references to uninitialized data,
        // which is illegal since the compiler is allowed to assume that a reference
        // points to valid data.
        // However, currently we just cannot avoid UB completely.
        let val = $crate::mem::MaybeUninit::<$parent>::uninit();
        let base_ptr = val.as_ptr();
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
        let offset = (field_ptr as usize) - (base_ptr as usize);
        offset
    }};
}

#[macro_export]
#[cfg(not(memoffset_maybe_uninit))]
macro_rules! offset_of {
    ($parent:tt, $field:tt) => {{
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        let $parent { $field: _, .. };

        // This is UB since we're dealing with dangling references.
        // We're never dereferencing it, but it's UB nonetheless.
        // See above for a better version that only works with newer Rust.
        let non_null = $crate::ptr::NonNull::<$parent>::dangling();
        #[allow(unused_unsafe)]
        let base_ptr = unsafe { non_null.as_ref() as *const $parent };
        #[allow(unused_unsafe)]
        let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
        let offset = (field_ptr as usize) - (base_ptr as usize);
        offset
    }};
}

#[cfg(test)]
mod tests {
    #[test]
    fn offset_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    #[cfg(not(miri))] // this creates unaligned references
    fn offset_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 6);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
        assert_eq!(offset_of!(Tup, 1), 4);
    }
}
<commit_msg>share the common code between the two offset_of implementations<commit_after>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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 OR COPYRIGHT HOLDERS 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.

/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as
/// much as is possible currently.
#[cfg(memoffset_maybe_uninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! let_base_ptr {
    ($name:ident, $type:tt) => {
        // No UB here, and the pointer does not dangle, either.
        let uninit = $crate::mem::MaybeUninit::<$type>::uninit();
        let $name = uninit.as_ptr();
    }
}
#[cfg(not(memoffset_maybe_uninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! let_base_ptr {
    ($name:ident, $type:tt) => {
        // No UB right here, but we will later offset into a field
        // of this pointer, and that is UB when the pointer is dangling.
        let non_null = $crate::ptr::NonNull::<$type>::dangling();
        let $name = non_null.as_ptr() as *const $type;
    }
}

/// Calculates the offset of the specified field from the start of the struct.
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
///
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
///
/// ## Examples
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
/// }
/// ```
#[macro_export]
macro_rules! offset_of {
    ($parent:tt, $field:tt) => {{
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        let $parent { $field: _, .. };

        // Get a base pointer.
        $crate::let_base_ptr!(base_ptr, $parent);
        // Get the field address. This is UB because we are creating a reference to
        // the uninitialized field.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
        let offset = (field_ptr as usize) - (base_ptr as usize);
        offset
    }};
}

#[cfg(test)]
mod tests {
    #[test]
    fn offset_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    #[cfg(not(miri))] // this creates unaligned references
    fn offset_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 6);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
        assert_eq!(offset_of!(Tup, 1), 4);
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

extern crate glutin;
extern crate cgmath;
extern crate serialize;

use cgmath::{Vector2, Vector3, deg};
use core_types::{Size2, ZInt, MapPos};
use visualizer_types::{ZFloat, Color3, Color4, ColorId, MatId, WorldPos, ScreenPos, VertexCoord};
use zgl::{Zgl, Mesh};
use camera::Camera;
use shader::{Shader};
use geom;
use core_map::{MapPosIter};

static VS_SRC: &'static str = "\
    #version 100\n\
    uniform mat4 mvp_mat;\n\
    attribute vec2 position;\n\
    void main() {\n\
        gl_Position = mvp_mat * vec4(position, 0.0, 1.0);\n\
    }\n\
";

static FS_SRC: &'static str = "\
    #version 100\n\
    precision mediump float;
    uniform vec4 col;\n\
    void main() {\n\
        gl_FragColor = col;\n\
    }\n\
";

fn get_win_size(window: &glutin::Window) -> Size2<ZInt> {
    let (w, h) = window.get_inner_size().expect("Can`t get window size");
    Size2{w: w as ZInt, h: h as ZInt}
}

fn get_max_camera_pos(map_size: &Size2<ZInt>) -> WorldPos {
    let pos = geom::map_pos_to_world_pos(
        MapPos{v: Vector2{x: map_size.w, y: map_size.h - 1}});
    WorldPos{v: Vector3{x: -pos.v.x, y: -pos.v.y, z: 0.0}}
}

fn generate_mesh(map_size: &Size2<ZInt>, zgl: &Zgl) -> Mesh {
    let mut vertex_data = Vec::new();
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom::map_pos_to_world_pos(tile_pos);
        // TODO: range(0, 6) -> some dir iterator
        for num in range(0i32, 6) {
            let vertex = geom::index_to_hex_vertex(num);
            let next_vertex = geom::index_to_hex_vertex(num + 1);
            vertex_data.push(VertexCoord{v: pos.v + vertex.v});
            vertex_data.push(VertexCoord{v: pos.v + next_vertex.v});
            vertex_data.push(VertexCoord{v: pos.v});
        }
    }
    Mesh::new(zgl, vertex_data.as_slice())
}

pub struct Visualizer {
    zgl: Zgl,
    window: glutin::Window,
    should_close: bool,
    color_counter: i32, // TODO: remove
    test_color: Color4,
    shader: Shader,
    color_uniform_location: ColorId,
    mvp_uniform_location: MatId,
    camera: Camera,
    mouse_pos: ScreenPos,
    is_lmb_pressed: bool,
    win_size: Size2<ZInt>,
    mesh: Mesh,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window_builder = glutin::WindowBuilder::new().with_gl_version((2, 0));
        let window = window_builder.build().ok().expect("Can`t create window");
        unsafe {
            window.make_current();
        };
        let win_size = get_win_size(&window);
        let mut zgl = Zgl::new(|s| window.get_proc_address(s));
        zgl.print_gl_info();
        let shader = Shader::new(&zgl, VS_SRC, FS_SRC);
        let color_uniform_location = shader.get_uniform_color(&zgl, "col");
        let mvp_uniform_location = shader.get_uniform_mat(&zgl, "mvp_mat");
        zgl.set_clear_color(Color3{r: 0.0, g: 0.0, b: 0.4});
        let mut camera = Camera::new(&win_size);
        let map_size = Size2{w: 5, h: 2};
        camera.set_max_pos(get_max_camera_pos(&map_size));
        let mesh = generate_mesh(&map_size, &zgl);
        Visualizer {
            zgl: zgl,
            window: window,
            should_close: false,
            color_counter: 0,
            test_color: Color4{r: 0.0, g: 0.0, b: 0.0, a: 0.0},
            shader: shader,
            color_uniform_location: color_uniform_location,
            mvp_uniform_location: mvp_uniform_location,
            camera: camera,
            mouse_pos: ScreenPos{v: Vector2::from_value(0)},
            is_lmb_pressed: false,
            win_size: win_size,
            mesh: mesh,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_event_key_press(&mut self, key: glutin::VirtualKeyCode) {
        match key {
            glutin::VirtualKeyCode::Q | glutin::VirtualKeyCode::Escape => {
                self.should_close = true;
            },
            glutin::VirtualKeyCode::W => self.camera.move_camera(deg(270.0), 0.1),
            glutin::VirtualKeyCode::S => self.camera.move_camera(deg(90.0), 0.1),
            glutin::VirtualKeyCode::D => self.camera.move_camera(deg(0.0), 0.1),
            glutin::VirtualKeyCode::A => self.camera.move_camera(deg(180.0), 0.1),
            glutin::VirtualKeyCode::Minus => self.camera.change_zoom(1.3),
            glutin::VirtualKeyCode::Equals => self.camera.change_zoom(0.7),
            _ => {},
        }
    }

    fn handle_event(&mut self, event: &glutin::Event) {
        match *event {
            glutin::Event::Closed => {
                self.should_close = true;
            },
            glutin::Event::Resized(w, h) => {
                self.win_size = Size2{w: w as ZInt, h: h as ZInt};
                self.zgl.set_viewport(&self.win_size);
            },
            glutin::Event::MouseMoved((x, y)) => {
                let new_pos = ScreenPos{v: Vector2{x: x as ZInt, y: y as ZInt}};
                if self.is_lmb_pressed {
                    let diff = new_pos.v - self.mouse_pos.v;
                    let win_w = self.win_size.w as ZFloat;
                    let win_h = self.win_size.h as ZFloat;
                    self.camera.add_z_angle(deg(diff.x as ZFloat * (360.0 / win_w)));
                    self.camera.add_x_angle(deg(diff.y as ZFloat * (360.0 / win_h)));
                }
                self.mouse_pos = new_pos;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Pressed,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = true;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Released,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = false;
                let (r, g, b, a) = self.zgl.read_pixel_bytes(
                    &self.win_size, &self.mouse_pos);
                println!("r: {}, g: {}, b: {}, a: {}", r, g, b, a);
            },
            glutin::Event::KeyboardInput(
                glutin::ElementState::Released, _, Some(key)) =>
            {
                self.handle_event_key_press(key);
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if events.is_empty() {
            return;
        }
        // println!("{}", events);
        for event in events.iter() {
            self.handle_event(event);
        }
    }

    fn update_test_color(&mut self) {
        self.test_color = match self.color_counter {
            0 => Color4{r: 1.0, g: 0.0, b: 0.0, a: 1.0},
            30 => Color4{r: 0.0, g: 1.0, b: 0.0, a: 1.0},
            60 => Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0},
            _ => self.test_color.clone(),
        };
        self.color_counter += 1;
        if self.color_counter > 90 {
            self.color_counter = -1;
        }
    }

    fn draw(&mut self) {
        self.zgl.clear_screen();
        self.shader.activate(&self.zgl);
        self.shader.set_uniform_color(
            &self.zgl, &self.color_uniform_location, &self.test_color);
        self.shader.set_uniform_mat4f(
            &self.zgl, &self.mvp_uniform_location, &self.camera.mat(&self.zgl));
        self.mesh.draw(&self.zgl);
        self.window.swap_buffers();
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.update_test_color();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/visualizer.rs: Extracted handle_event_mouse_move<commit_after>// See LICENSE file for copyright and license details.

extern crate glutin;
extern crate cgmath;
extern crate serialize;

use cgmath::{Vector2, Vector3, deg};
use core_types::{Size2, ZInt, MapPos};
use visualizer_types::{ZFloat, Color3, Color4, ColorId, MatId, WorldPos, ScreenPos, VertexCoord};
use zgl::{Zgl, Mesh};
use camera::Camera;
use shader::{Shader};
use geom;
use core_map::{MapPosIter};

static VS_SRC: &'static str = "\
    #version 100\n\
    uniform mat4 mvp_mat;\n\
    attribute vec2 position;\n\
    void main() {\n\
        gl_Position = mvp_mat * vec4(position, 0.0, 1.0);\n\
    }\n\
";

static FS_SRC: &'static str = "\
    #version 100\n\
    precision mediump float;
    uniform vec4 col;\n\
    void main() {\n\
        gl_FragColor = col;\n\
    }\n\
";

fn get_win_size(window: &glutin::Window) -> Size2<ZInt> {
    let (w, h) = window.get_inner_size().expect("Can`t get window size");
    Size2{w: w as ZInt, h: h as ZInt}
}

fn get_max_camera_pos(map_size: &Size2<ZInt>) -> WorldPos {
    let pos = geom::map_pos_to_world_pos(
        MapPos{v: Vector2{x: map_size.w, y: map_size.h - 1}});
    WorldPos{v: Vector3{x: -pos.v.x, y: -pos.v.y, z: 0.0}}
}

fn generate_mesh(map_size: &Size2<ZInt>, zgl: &Zgl) -> Mesh {
    let mut vertex_data = Vec::new();
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom::map_pos_to_world_pos(tile_pos);
        // TODO: range(0, 6) -> some dir iterator
        for num in range(0i32, 6) {
            let vertex = geom::index_to_hex_vertex(num);
            let next_vertex = geom::index_to_hex_vertex(num + 1);
            vertex_data.push(VertexCoord{v: pos.v + vertex.v});
            vertex_data.push(VertexCoord{v: pos.v + next_vertex.v});
            vertex_data.push(VertexCoord{v: pos.v});
        }
    }
    Mesh::new(zgl, vertex_data.as_slice())
}

pub struct Visualizer {
    zgl: Zgl,
    window: glutin::Window,
    should_close: bool,
    color_counter: i32, // TODO: remove
    test_color: Color4,
    shader: Shader,
    color_uniform_location: ColorId,
    mvp_uniform_location: MatId,
    camera: Camera,
    mouse_pos: ScreenPos,
    is_lmb_pressed: bool,
    win_size: Size2<ZInt>,
    mesh: Mesh,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window_builder = glutin::WindowBuilder::new().with_gl_version((2, 0));
        let window = window_builder.build().ok().expect("Can`t create window");
        unsafe {
            window.make_current();
        };
        let win_size = get_win_size(&window);
        let mut zgl = Zgl::new(|s| window.get_proc_address(s));
        zgl.print_gl_info();
        let shader = Shader::new(&zgl, VS_SRC, FS_SRC);
        let color_uniform_location = shader.get_uniform_color(&zgl, "col");
        let mvp_uniform_location = shader.get_uniform_mat(&zgl, "mvp_mat");
        zgl.set_clear_color(Color3{r: 0.0, g: 0.0, b: 0.4});
        let mut camera = Camera::new(&win_size);
        let map_size = Size2{w: 5, h: 2};
        camera.set_max_pos(get_max_camera_pos(&map_size));
        let mesh = generate_mesh(&map_size, &zgl);
        Visualizer {
            zgl: zgl,
            window: window,
            should_close: false,
            color_counter: 0,
            test_color: Color4{r: 0.0, g: 0.0, b: 0.0, a: 0.0},
            shader: shader,
            color_uniform_location: color_uniform_location,
            mvp_uniform_location: mvp_uniform_location,
            camera: camera,
            mouse_pos: ScreenPos{v: Vector2::from_value(0)},
            is_lmb_pressed: false,
            win_size: win_size,
            mesh: mesh,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_event_mouse_move(&mut self, pos: &ScreenPos) {
        if self.is_lmb_pressed {
            let diff = pos.v - self.mouse_pos.v;
            let win_w = self.win_size.w as ZFloat;
            let win_h = self.win_size.h as ZFloat;
            self.camera.add_z_angle(
                deg(diff.x as ZFloat * (360.0 / win_w)));
            self.camera.add_x_angle(
                deg(diff.y as ZFloat * (360.0 / win_h)));
        }
        self.mouse_pos = pos.clone();
    }

    fn handle_event_key_press(&mut self, key: glutin::VirtualKeyCode) {
        match key {
            glutin::VirtualKeyCode::Q | glutin::VirtualKeyCode::Escape => {
                self.should_close = true;
            },
            glutin::VirtualKeyCode::W => self.camera.move_camera(deg(270.0), 0.1),
            glutin::VirtualKeyCode::S => self.camera.move_camera(deg(90.0), 0.1),
            glutin::VirtualKeyCode::D => self.camera.move_camera(deg(0.0), 0.1),
            glutin::VirtualKeyCode::A => self.camera.move_camera(deg(180.0), 0.1),
            glutin::VirtualKeyCode::Minus => self.camera.change_zoom(1.3),
            glutin::VirtualKeyCode::Equals => self.camera.change_zoom(0.7),
            _ => {},
        }
    }

    fn handle_event(&mut self, event: &glutin::Event) {
        match *event {
            glutin::Event::Closed => {
                self.should_close = true;
            },
            glutin::Event::Resized(w, h) => {
                self.win_size = Size2{w: w as ZInt, h: h as ZInt};
                self.zgl.set_viewport(&self.win_size);
            },
            glutin::Event::MouseMoved((x, y)) => {
                let pos = ScreenPos{v: Vector2{x: x as ZInt, y: y as ZInt}};
                self.handle_event_mouse_move(&pos);
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Pressed,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = true;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Released,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = false;
                let (r, g, b, a) = self.zgl.read_pixel_bytes(
                    &self.win_size, &self.mouse_pos);
                println!("r: {}, g: {}, b: {}, a: {}", r, g, b, a);
            },
            glutin::Event::KeyboardInput(
                glutin::ElementState::Released, _, Some(key)) =>
            {
                self.handle_event_key_press(key);
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if events.is_empty() {
            return;
        }
        // println!("{}", events);
        for event in events.iter() {
            self.handle_event(event);
        }
    }

    fn update_test_color(&mut self) {
        self.test_color = match self.color_counter {
            0 => Color4{r: 1.0, g: 0.0, b: 0.0, a: 1.0},
            30 => Color4{r: 0.0, g: 1.0, b: 0.0, a: 1.0},
            60 => Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0},
            _ => self.test_color.clone(),
        };
        self.color_counter += 1;
        if self.color_counter > 90 {
            self.color_counter = -1;
        }
    }

    fn draw(&mut self) {
        self.zgl.clear_screen();
        self.shader.activate(&self.zgl);
        self.shader.set_uniform_color(
            &self.zgl, &self.color_uniform_location, &self.test_color);
        self.shader.set_uniform_mat4f(
            &self.zgl, &self.mvp_uniform_location, &self.camera.mat(&self.zgl));
        self.mesh.draw(&self.zgl);
        self.window.swap_buffers();
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.update_test_color();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use crate::web::{INDEX_JS, MENU_JS};
use iron::middleware::Handler;
use iron::Request;
use router::Router;
use std::collections::HashSet;

const DOC_RUST_LANG_ORG_REDIRECTS: &[&str] = &["alloc", "core", "proc_macro", "std", "test"];

// REFACTOR: Break this into smaller initialization functions
pub(super) fn build_routes() -> Routes {
    let mut routes = Routes::new();

    routes.static_resource("/style.css", super::style_css_handler);
    routes.static_resource("/index.js", |_: &mut Request| super::load_js(INDEX_JS));
    routes.static_resource("/menu.js", |_: &mut Request| super::load_js(MENU_JS));
    routes.static_resource("/robots.txt", super::sitemap::robots_txt_handler);
    routes.static_resource("/sitemap.xml", super::sitemap::sitemap_handler);
    routes.static_resource("/opensearch.xml", super::opensearch_xml_handler);

    routes.internal_page("/", super::releases::home_page);

    routes.internal_page("/about", super::sitemap::about_handler);
    routes.internal_page("/about/metrics", super::metrics::metrics_handler);

    routes.internal_page("/releases", super::releases::recent_releases_handler);
    routes.static_resource("/releases/feed", super::releases::releases_feed_handler);
    routes.internal_page("/releases/:author", super::releases::author_handler);
    routes.internal_page("/releases/:author/:page", super::releases::author_handler);
    routes.internal_page("/releases/activity", super::releases::activity_handler);
    routes.internal_page("/releases/search", super::releases::search_handler);
    routes.internal_page("/releases/queue", super::releases::build_queue_handler);
    routes.internal_page(
        "/releases/recent/:page",
        super::releases::recent_releases_handler,
    );
    routes.internal_page(
        "/releases/stars",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/stars/:page",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/recent-failures",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/recent-failures/:page",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/failures",
        super::releases::releases_failures_by_stars_handler,
    );
    routes.internal_page(
        "/releases/failures/:page",
        super::releases::releases_failures_by_stars_handler,
    );

    routes.internal_page("/crate/:name", super::crate_details::crate_details_handler);
    routes.internal_page(
        "/crate/:name/:version",
        super::crate_details::crate_details_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds",
        super::builds::build_list_handler,
    );
    routes.static_resource(
        "/crate/:name/:version/builds.json",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds/:id",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source",
        SimpleRedirect::new(|url| url.set_path(&format!("{}/", url.path()))),
    );
    routes.internal_page(
        "/crate/:name/:version/source/",
        super::source::source_browser_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source/*",
        super::source::source_browser_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/target-redirect/*",
        super::rustdoc::target_redirect_handler,
    );

    routes.rustdoc_page("/:crate", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/badge.svg", super::rustdoc::badge_handler);
    routes.rustdoc_page(
        "/:crate/:version",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/settings.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/all.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/*.html",
        super::rustdoc::rustdoc_html_server_handler,
    );

    for redirect in DOC_RUST_LANG_ORG_REDIRECTS {
        routes.internal_page(
            &format!("/{}", redirect),
            super::rustdoc::RustLangRedirector::new(redirect),
        );
    }

    routes
}

/// This wrapper class aids the construction of iron's Router, with docs.rs-specific additions to
/// it. Routes are supposed to be added by the build_routes function, which calls methods in this
/// struct depending on the type of route being added.
pub(super) struct Routes {
    /// Normal GET routes.
    get: Vec<(String, Box<dyn Handler>)>,
    /// GET routes serving rustdoc content. The BlockBlacklistedPrefixes middleware is added
    /// automatically to all of them.
    rustdoc_get: Vec<(String, Box<dyn Handler>)>,
    /// Prefixes of all the internal routes. This data is used to power the
    /// BlockBlacklistedPrefixes middleware.
    page_prefixes: HashSet<String>,
}

impl Routes {
    fn new() -> Self {
        Self {
            get: Vec::new(),
            rustdoc_get: Vec::new(),
            page_prefixes: HashSet::new(),
        }
    }

    pub(super) fn page_prefixes(&self) -> HashSet<String> {
        self.page_prefixes.clone()
    }

    pub(super) fn iron_router(mut self) -> Router {
        let mut router = Router::new();
        for (pattern, handler) in self.get.drain(..) {
            router.get(&pattern, handler, calculate_id(&pattern));
        }

        // All rustdoc pages have the prefixes of other docs.rs pages blacklisted. This prevents,
        // for example, a crate named "about" from hijacking /about/0.1.0/index.html.
        let blacklist = self.page_prefixes();
        for (pattern, handler) in self.rustdoc_get.drain(..) {
            router.get(
                &pattern,
                BlockBlacklistedPrefixes::new(blacklist.clone(), handler),
                calculate_id(&pattern),
            );
        }

        router
    }

    /// A static resource is a normal page without any special behavior on the router side.
    fn static_resource(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));
    }

    /// Internal pages are docs.rs's own pages, instead of the documentation of a crate uploaded by
    /// an user. The router adds these extra things when adding a new internal page:
    ///
    /// - The first component of the page's URL will be registered as a "page prefix". Page
    /// prefixes are blacklisted by rustdoc pages, to prevent a crate named the same as a prefix
    /// from hijacking docs.rs's own URLs.
    ///
    /// - If the page URL doesn't end with a slash, a redirect from the URL with the trailing slash
    /// to the one without is automatically added.
    fn internal_page(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));

        // Automatically add another route ending with / that redirects to the slash-less route.
        if !pattern.ends_with('/') {
            let pattern = format!("{}/", pattern);
            self.get.push((
                pattern,
                Box::new(SimpleRedirect::new(|url| {
                    url.set_path(&url.path().trim_end_matches('/').to_string())
                })),
            ));
        }

        // Register the prefix if it's not the home page and the first path component is not a
        // pattern or a wildcard.
        if pattern != "/" {
            if let Some(first_component) = pattern.trim_matches('/').split('/').next() {
                if !first_component.contains('*') && !first_component.starts_with(':') {
                    self.page_prefixes.insert(first_component.to_string());
                }
            }
        }
    }

    /// A rustdoc page is a page serving generated documentation. It's similar to a static
    /// resource, but path prefixes are automatically blacklisted (see internal pages to learn more
    /// about page prefixes).
    fn rustdoc_page(&mut self, pattern: &str, handler: impl Handler) {
        self.rustdoc_get
            .push((pattern.to_string(), Box::new(handler)));
    }
}

#[derive(Copy, Clone)]
struct SimpleRedirect {
    url_mangler: fn(&mut iron::url::Url),
}

impl SimpleRedirect {
    fn new(url_mangler: fn(&mut iron::url::Url)) -> Self {
        Self { url_mangler }
    }
}

impl Handler for SimpleRedirect {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        let mut url: iron::url::Url = req.url.clone().into();
        (self.url_mangler)(&mut url);
        Ok(iron::Response::with((
            iron::status::Found,
            iron::modifiers::Redirect(iron::Url::parse(&url.to_string()).unwrap()),
        )))
    }
}

/// Iron Middleware that prevents requests to blacklisted prefixes.
///
/// In our application, a prefix is blacklisted if a docs.rs page exists below it. For example,
/// since /releases/queue is a docs.rs page, /releases is a blacklisted prefix.
///
/// The middleware must be used for all the pages serving crates at the top level, to prevent a
/// crate from putting their own content in an URL that's supposed to be used by docs.rs.
pub(super) struct BlockBlacklistedPrefixes {
    blacklist: HashSet<String>,
    handler: Box<dyn Handler>,
}

impl BlockBlacklistedPrefixes {
    pub(super) fn new(blacklist: HashSet<String>, handler: Box<dyn Handler>) -> Self {
        Self { blacklist, handler }
    }
}

impl Handler for BlockBlacklistedPrefixes {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        if let Some(prefix) = req.url.path().get(0) {
            if self.blacklist.contains(*prefix) {
                return Err(iron::IronError::new(
                    super::error::Nope::CrateNotFound,
                    iron::status::NotFound,
                ));
            }
        }
        self.handler.handle(req)
    }
}

/// Automatically generate a Route ID from a pattern. Every non-alphanumeric character is replaced
/// with `_`.
fn calculate_id(pattern: &str) -> String {
    pattern
        .chars()
        .map(|c| if c.is_alphanumeric() { c } else { '_' })
        .collect()
}
<commit_msg>Revert redirector handler for path /:crate/:version/:target/<commit_after>use crate::web::{INDEX_JS, MENU_JS};
use iron::middleware::Handler;
use iron::Request;
use router::Router;
use std::collections::HashSet;

const DOC_RUST_LANG_ORG_REDIRECTS: &[&str] = &["alloc", "core", "proc_macro", "std", "test"];

// REFACTOR: Break this into smaller initialization functions
pub(super) fn build_routes() -> Routes {
    let mut routes = Routes::new();

    routes.static_resource("/style.css", super::style_css_handler);
    routes.static_resource("/index.js", |_: &mut Request| super::load_js(INDEX_JS));
    routes.static_resource("/menu.js", |_: &mut Request| super::load_js(MENU_JS));
    routes.static_resource("/robots.txt", super::sitemap::robots_txt_handler);
    routes.static_resource("/sitemap.xml", super::sitemap::sitemap_handler);
    routes.static_resource("/opensearch.xml", super::opensearch_xml_handler);

    routes.internal_page("/", super::releases::home_page);

    routes.internal_page("/about", super::sitemap::about_handler);
    routes.internal_page("/about/metrics", super::metrics::metrics_handler);

    routes.internal_page("/releases", super::releases::recent_releases_handler);
    routes.static_resource("/releases/feed", super::releases::releases_feed_handler);
    routes.internal_page("/releases/:author", super::releases::author_handler);
    routes.internal_page("/releases/:author/:page", super::releases::author_handler);
    routes.internal_page("/releases/activity", super::releases::activity_handler);
    routes.internal_page("/releases/search", super::releases::search_handler);
    routes.internal_page("/releases/queue", super::releases::build_queue_handler);
    routes.internal_page(
        "/releases/recent/:page",
        super::releases::recent_releases_handler,
    );
    routes.internal_page(
        "/releases/stars",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/stars/:page",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/recent-failures",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/recent-failures/:page",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/failures",
        super::releases::releases_failures_by_stars_handler,
    );
    routes.internal_page(
        "/releases/failures/:page",
        super::releases::releases_failures_by_stars_handler,
    );

    routes.internal_page("/crate/:name", super::crate_details::crate_details_handler);
    routes.internal_page(
        "/crate/:name/:version",
        super::crate_details::crate_details_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds",
        super::builds::build_list_handler,
    );
    routes.static_resource(
        "/crate/:name/:version/builds.json",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds/:id",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source",
        SimpleRedirect::new(|url| url.set_path(&format!("{}/", url.path()))),
    );
    routes.internal_page(
        "/crate/:name/:version/source/",
        super::source::source_browser_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source/*",
        super::source::source_browser_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/target-redirect/*",
        super::rustdoc::target_redirect_handler,
    );

    routes.rustdoc_page("/:crate", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/badge.svg", super::rustdoc::badge_handler);
    routes.rustdoc_page(
        "/:crate/:version",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/settings.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/all.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/*.html",
        super::rustdoc::rustdoc_html_server_handler,
    );

    for redirect in DOC_RUST_LANG_ORG_REDIRECTS {
        routes.internal_page(
            &format!("/{}", redirect),
            super::rustdoc::RustLangRedirector::new(redirect),
        );
    }

    routes
}

/// This wrapper class aids the construction of iron's Router, with docs.rs-specific additions to
/// it. Routes are supposed to be added by the build_routes function, which calls methods in this
/// struct depending on the type of route being added.
pub(super) struct Routes {
    /// Normal GET routes.
    get: Vec<(String, Box<dyn Handler>)>,
    /// GET routes serving rustdoc content. The BlockBlacklistedPrefixes middleware is added
    /// automatically to all of them.
    rustdoc_get: Vec<(String, Box<dyn Handler>)>,
    /// Prefixes of all the internal routes. This data is used to power the
    /// BlockBlacklistedPrefixes middleware.
    page_prefixes: HashSet<String>,
}

impl Routes {
    fn new() -> Self {
        Self {
            get: Vec::new(),
            rustdoc_get: Vec::new(),
            page_prefixes: HashSet::new(),
        }
    }

    pub(super) fn page_prefixes(&self) -> HashSet<String> {
        self.page_prefixes.clone()
    }

    pub(super) fn iron_router(mut self) -> Router {
        let mut router = Router::new();
        for (pattern, handler) in self.get.drain(..) {
            router.get(&pattern, handler, calculate_id(&pattern));
        }

        // All rustdoc pages have the prefixes of other docs.rs pages blacklisted. This prevents,
        // for example, a crate named "about" from hijacking /about/0.1.0/index.html.
        let blacklist = self.page_prefixes();
        for (pattern, handler) in self.rustdoc_get.drain(..) {
            router.get(
                &pattern,
                BlockBlacklistedPrefixes::new(blacklist.clone(), handler),
                calculate_id(&pattern),
            );
        }

        router
    }

    /// A static resource is a normal page without any special behavior on the router side.
    fn static_resource(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));
    }

    /// Internal pages are docs.rs's own pages, instead of the documentation of a crate uploaded by
    /// an user. The router adds these extra things when adding a new internal page:
    ///
    /// - The first component of the page's URL will be registered as a "page prefix". Page
    /// prefixes are blacklisted by rustdoc pages, to prevent a crate named the same as a prefix
    /// from hijacking docs.rs's own URLs.
    ///
    /// - If the page URL doesn't end with a slash, a redirect from the URL with the trailing slash
    /// to the one without is automatically added.
    fn internal_page(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));

        // Automatically add another route ending with / that redirects to the slash-less route.
        if !pattern.ends_with('/') {
            let pattern = format!("{}/", pattern);
            self.get.push((
                pattern,
                Box::new(SimpleRedirect::new(|url| {
                    url.set_path(&url.path().trim_end_matches('/').to_string())
                })),
            ));
        }

        // Register the prefix if it's not the home page and the first path component is not a
        // pattern or a wildcard.
        if pattern != "/" {
            if let Some(first_component) = pattern.trim_matches('/').split('/').next() {
                if !first_component.contains('*') && !first_component.starts_with(':') {
                    self.page_prefixes.insert(first_component.to_string());
                }
            }
        }
    }

    /// A rustdoc page is a page serving generated documentation. It's similar to a static
    /// resource, but path prefixes are automatically blacklisted (see internal pages to learn more
    /// about page prefixes).
    fn rustdoc_page(&mut self, pattern: &str, handler: impl Handler) {
        self.rustdoc_get
            .push((pattern.to_string(), Box::new(handler)));
    }
}

#[derive(Copy, Clone)]
struct SimpleRedirect {
    url_mangler: fn(&mut iron::url::Url),
}

impl SimpleRedirect {
    fn new(url_mangler: fn(&mut iron::url::Url)) -> Self {
        Self { url_mangler }
    }
}

impl Handler for SimpleRedirect {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        let mut url: iron::url::Url = req.url.clone().into();
        (self.url_mangler)(&mut url);
        Ok(iron::Response::with((
            iron::status::Found,
            iron::modifiers::Redirect(iron::Url::parse(&url.to_string()).unwrap()),
        )))
    }
}

/// Iron Middleware that prevents requests to blacklisted prefixes.
///
/// In our application, a prefix is blacklisted if a docs.rs page exists below it. For example,
/// since /releases/queue is a docs.rs page, /releases is a blacklisted prefix.
///
/// The middleware must be used for all the pages serving crates at the top level, to prevent a
/// crate from putting their own content in an URL that's supposed to be used by docs.rs.
pub(super) struct BlockBlacklistedPrefixes {
    blacklist: HashSet<String>,
    handler: Box<dyn Handler>,
}

impl BlockBlacklistedPrefixes {
    pub(super) fn new(blacklist: HashSet<String>, handler: Box<dyn Handler>) -> Self {
        Self { blacklist, handler }
    }
}

impl Handler for BlockBlacklistedPrefixes {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        if let Some(prefix) = req.url.path().get(0) {
            if self.blacklist.contains(*prefix) {
                return Err(iron::IronError::new(
                    super::error::Nope::CrateNotFound,
                    iron::status::NotFound,
                ));
            }
        }
        self.handler.handle(req)
    }
}

/// Automatically generate a Route ID from a pattern. Every non-alphanumeric character is replaced
/// with `_`.
fn calculate_id(pattern: &str) -> String {
    pattern
        .chars()
        .map(|c| if c.is_alphanumeric() { c } else { '_' })
        .collect()
}
<|endoftext|>