<commit_before>extern crate glium;

use std::mem::zeroed;
use std::ops::*;
use glium::uniforms::*;

pub trait Vector {
    fn transform(self, matrix: &Matrix) -> Self;
}

type Vector2 = (f32, f32);

impl Vector for Vector2 {
    fn transform(self, matrix: &Matrix) -> Self {
        let m = matrix.m;

        let x = self.0*m[0][0] + self.1*m[1][0];
        let y = self.0*m[0][1] + self.1*m[1][1];
        (x, y)
    }
}

#[test]
fn transform_vector2() {
    let matrix = Matrix {
        m: [
            [ 2.0, 3.0, 5.0, 7.0 ],
            [ 11.0, 13.0, 17.0, 19.0 ],
            [ 23.0, 29.0, 31.0, 37.0 ],
            [ 41.0, 43.0, 47.0, 53.0 ],
        ]
    };

    let origin = (1.0, 1.0);

    let transformed = origin.transform(&matrix);

    assert_eq!(transformed.0, 13.0);
    assert_eq!(transformed.1, 16.0);
}

#[derive(PartialEq, Clone, Debug)]
pub struct Matrix { m: [[f32; 4]; 4] }

impl Matrix {
    pub fn new() -> Self { unsafe { zeroed() } }

    pub fn identity() -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_x(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [1.0,  0.0, 0.0, 0.0],
                [0.0,  cos, sin, 0.0],
                [0.0, -sin, cos, 0.0],
                [0.0,  0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_y(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [cos, 0.0, -sin, 0.0],
                [0.0, 1.0,  0.0, 0.0],
                [sin, 0.0,  cos, 0.0],
                [0.0, 0.0,  0.0, 1.0],
            ]
        }
    }

    pub fn rotation_z(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [ cos, sin, 0.0, 0.0],
                [-sin, cos, 0.0, 0.0],
                [ 0.0, 0.0, 1.0, 0.0],
                [ 0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn orthographic(view_width: f32, view_height: f32, near_z: f32, far_z: f32) -> Self {
        // assert(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
        let f_range = 1.0/(near_z - far_z);
        Matrix {
            m: [
                [2.0/view_width, 0.0, 0.0, 0.0],
                [0.0, 2.0/view_height, 0.0, 0.0],
                [0.0, 0.0, f_range, 0.0],
                [0.0, 0.0, f_range*near_z, 1.0],
            ]
        }

    }

    pub fn orthographic_off_center(view_left: f32, view_right: f32, view_bottom: f32, view_top: f32, near_z: f32, far_z: f32) -> Self {
        // reciprocal width and height
        let r_width = 1.0/(view_right - view_left);
        let r_height = 1.0/(view_top - view_bottom);
        let range = 1.0/(near_z-far_z);

        Matrix {
            m: [
                [r_width + r_width, 0.0, 0.0, 0.0],
                [0.0, r_height + r_height, 0.0, 0.0],
                [0.0, 0.0, range, 0.0],
                [-(view_left + view_right)*r_width, -(view_top + view_bottom)*r_height, range*near_z, 1.0],
            ]
        }
    }

    pub fn perspective(width: f32, height: f32, near_z: f32, far_z: f32) -> Self {
        let two_near_z = near_z + near_z;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [two_near_z/width, 0.0, 0.0, 0.0],
                [0.0, two_near_z/height, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    /// aspect: Width / Height
    pub fn perspective_fov(fov: f32, aspect: f32, near_z: f32, far_z: f32) -> Self {
        let (sin, cos) = (0.5 * fov).sin_cos();
        let f = cos/sin;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [f/aspect, 0.0, 0.0, 0.0],
                [0.0, f, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    pub fn translation(ox: f32, oy: f32, oz: f32) -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [ox,  oy,  oz,  1.0],
            ]
        }
    }

    pub fn transpose(self) -> Self {
        Matrix {
            m: [
                [self.m[0][0], self.m[1][0], self.m[2][0], self.m[3][0]],
                [self.m[0][1], self.m[1][1], self.m[2][1], self.m[3][1]],
                [self.m[0][2], self.m[1][2], self.m[2][2], self.m[3][2]],
                [self.m[0][3], self.m[1][3], self.m[2][3], self.m[3][3]],
            ]
        }
    }
}

#[test]
fn new_matrix_is_zeroed() {
    let m = Matrix::new();

    assert_eq!(m.m[0][0], 0.0);
    assert_eq!(m.m[0][1], 0.0);
    assert_eq!(m.m[0][2], 0.0);
    assert_eq!(m.m[0][3], 0.0);
    assert_eq!(m.m[1][0], 0.0);
    assert_eq!(m.m[1][1], 0.0);
    assert_eq!(m.m[1][2], 0.0);
    assert_eq!(m.m[1][3], 0.0);
    assert_eq!(m.m[2][0], 0.0);
    assert_eq!(m.m[2][1], 0.0);
    assert_eq!(m.m[2][2], 0.0);
    assert_eq!(m.m[2][3], 0.0);
    assert_eq!(m.m[3][0], 0.0);
    assert_eq!(m.m[3][1], 0.0);
    assert_eq!(m.m[3][2], 0.0);
    assert_eq!(m.m[3][3], 0.0);
}

impl Mul for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { &self * &rhs }
}

impl<'a> Mul<Matrix> for &'a Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { self * &rhs }
}

impl<'a> Mul<&'a Matrix> for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: &'a Matrix) -> Matrix { &self * rhs }
}

impl<'a, 'b> Mul<&'a Matrix> for &'b Matrix {
    type Output = Matrix;

    fn mul(self, rhs: &'a Matrix) -> Matrix {
        macro_rules! row {
            ($col:expr) => ({
                let x = self.m[$col][0];
                let y = self.m[$col][1];
                let z = self.m[$col][2];
                let w = self.m[$col][3];
                [
                    (rhs.m[0][0]*x)+(rhs.m[1][0]*y)+(rhs.m[2][0]*z)+(rhs.m[3][0]*w),
                    (rhs.m[0][1]*x)+(rhs.m[1][1]*y)+(rhs.m[2][1]*z)+(rhs.m[3][1]*w),
                    (rhs.m[0][2]*x)+(rhs.m[1][2]*y)+(rhs.m[2][2]*z)+(rhs.m[3][2]*w),
                    (rhs.m[0][3]*x)+(rhs.m[1][3]*y)+(rhs.m[2][3]*z)+(rhs.m[3][3]*w),
                ]
            })
        }

        Matrix { m: [ row!(0), row!(1), row!(2), row!(3) ] }
    }
}

impl AsUniformValue for Matrix {
    fn as_uniform_value(&self) -> UniformValue<'static> {
        UniformValue::Mat4(self.m)
    }

    fn matches(ty: &UniformType) -> bool {
        ty == &UniformType::FloatMat4
    }
}
<commit_msg>Implement transform method for Vector3 and Vector 4<commit_after>extern crate glium;

use std::mem::zeroed;
use std::ops::*;
use glium::uniforms::*;

pub trait Vector {
    fn transform(self, matrix: &Matrix) -> Self;
}

type Vector2 = (f32, f32);
type Vector3 = (f32, f32, f32);
type Vector4 = (f32, f32, f32, f32);

impl Vector for Vector2 {
    fn transform(self, matrix: &Matrix) -> Self {
        let m = matrix.m;

        let x = self.0*m[0][0] + self.1*m[1][0];
        let y = self.0*m[0][1] + self.1*m[1][1];
        (x, y)
    }
}

impl Vector for Vector3 {
    fn transform(self, matrix: &Matrix) -> Self {
        let m = matrix.m;

        let x = self.0*m[0][0] + self.1*m[1][0] + self.2*m[2][0];
        let y = self.0*m[0][1] + self.1*m[1][1] + self.2*m[2][1];
        let z = self.0*m[0][2] + self.1*m[1][2] + self.2*m[2][2];
        (x, y, z)
    }
}

impl Vector for Vector4 {
    fn transform(self, matrix: &Matrix) -> Self {
        let m = matrix.m;

        let x = self.0*m[0][0] + self.1*m[1][0] + self.2*m[2][0] + self.3*m[3][0];
        let y = self.0*m[0][1] + self.1*m[1][1] + self.2*m[2][1] + self.3*m[3][1];
        let z = self.0*m[0][2] + self.1*m[1][2] + self.2*m[2][2] + self.3*m[3][2];
        let w = self.0*m[0][3] + self.1*m[1][3] + self.2*m[2][3] + self.3*m[3][3];
        (x, y, z, w)
    }
}

#[test]
fn transform_vector2() {
    let matrix = Matrix {
        m: [
            [ 2.0, 3.0, 5.0, 7.0 ],
            [ 11.0, 13.0, 17.0, 19.0 ],
            [ 23.0, 29.0, 31.0, 37.0 ],
            [ 41.0, 43.0, 47.0, 53.0 ],
        ]
    };

    let origin = (1.0, 1.0);

    let transformed = origin.transform(&matrix);

    assert_eq!(transformed.0, 13.0);
    assert_eq!(transformed.1, 16.0);
}

#[test]
fn transform_vector3() {
    let matrix = Matrix {
        m: [
            [ 2.0, 3.0, 5.0, 7.0 ],
            [ 11.0, 13.0, 17.0, 19.0 ],
            [ 23.0, 29.0, 31.0, 37.0 ],
            [ 41.0, 43.0, 47.0, 53.0 ],
        ]
    };

    let origin = (1.0, 1.0, 1.0);

    let transformed = origin.transform(&matrix);

    assert_eq!(transformed.0, 36.0);
    assert_eq!(transformed.1, 45.0);
    assert_eq!(transformed.2, 53.0);
}

#[test]
fn transform_vector4() {
    let matrix = Matrix {
        m: [
            [ 2.0, 3.0, 5.0, 7.0 ],
            [ 11.0, 13.0, 17.0, 19.0 ],
            [ 23.0, 29.0, 31.0, 37.0 ],
            [ 41.0, 43.0, 47.0, 53.0 ],
        ]
    };

    let origin = (1.0, 1.0, 1.0, 1.0);

    let transformed = origin.transform(&matrix);

    assert_eq!(transformed.0, 77.0);
    assert_eq!(transformed.1, 88.0);
    assert_eq!(transformed.2, 100.0);
    assert_eq!(transformed.3, 116.0);
}

#[derive(PartialEq, Clone, Debug)]
pub struct Matrix { m: [[f32; 4]; 4] }

impl Matrix {
    pub fn new() -> Self { unsafe { zeroed() } }

    pub fn identity() -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_x(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [1.0,  0.0, 0.0, 0.0],
                [0.0,  cos, sin, 0.0],
                [0.0, -sin, cos, 0.0],
                [0.0,  0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_y(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [cos, 0.0, -sin, 0.0],
                [0.0, 1.0,  0.0, 0.0],
                [sin, 0.0,  cos, 0.0],
                [0.0, 0.0,  0.0, 1.0],
            ]
        }
    }

    pub fn rotation_z(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [ cos, sin, 0.0, 0.0],
                [-sin, cos, 0.0, 0.0],
                [ 0.0, 0.0, 1.0, 0.0],
                [ 0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn orthographic(view_width: f32, view_height: f32, near_z: f32, far_z: f32) -> Self {
        // assert(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
        let f_range = 1.0/(near_z - far_z);
        Matrix {
            m: [
                [2.0/view_width, 0.0, 0.0, 0.0],
                [0.0, 2.0/view_height, 0.0, 0.0],
                [0.0, 0.0, f_range, 0.0],
                [0.0, 0.0, f_range*near_z, 1.0],
            ]
        }

    }

    pub fn orthographic_off_center(view_left: f32, view_right: f32, view_bottom: f32, view_top: f32, near_z: f32, far_z: f32) -> Self {
        // reciprocal width and height
        let r_width = 1.0/(view_right - view_left);
        let r_height = 1.0/(view_top - view_bottom);
        let range = 1.0/(near_z-far_z);

        Matrix {
            m: [
                [r_width + r_width, 0.0, 0.0, 0.0],
                [0.0, r_height + r_height, 0.0, 0.0],
                [0.0, 0.0, range, 0.0],
                [-(view_left + view_right)*r_width, -(view_top + view_bottom)*r_height, range*near_z, 1.0],
            ]
        }
    }

    pub fn perspective(width: f32, height: f32, near_z: f32, far_z: f32) -> Self {
        let two_near_z = near_z + near_z;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [two_near_z/width, 0.0, 0.0, 0.0],
                [0.0, two_near_z/height, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    /// aspect: Width / Height
    pub fn perspective_fov(fov: f32, aspect: f32, near_z: f32, far_z: f32) -> Self {
        let (sin, cos) = (0.5 * fov).sin_cos();
        let f = cos/sin;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [f/aspect, 0.0, 0.0, 0.0],
                [0.0, f, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    pub fn translation(ox: f32, oy: f32, oz: f32) -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [ox,  oy,  oz,  1.0],
            ]
        }
    }

    pub fn transpose(self) -> Self {
        Matrix {
            m: [
                [self.m[0][0], self.m[1][0], self.m[2][0], self.m[3][0]],
                [self.m[0][1], self.m[1][1], self.m[2][1], self.m[3][1]],
                [self.m[0][2], self.m[1][2], self.m[2][2], self.m[3][2]],
                [self.m[0][3], self.m[1][3], self.m[2][3], self.m[3][3]],
            ]
        }
    }
}

#[test]
fn new_matrix_is_zeroed() {
    let m = Matrix::new();

    assert_eq!(m.m[0][0], 0.0);
    assert_eq!(m.m[0][1], 0.0);
    assert_eq!(m.m[0][2], 0.0);
    assert_eq!(m.m[0][3], 0.0);
    assert_eq!(m.m[1][0], 0.0);
    assert_eq!(m.m[1][1], 0.0);
    assert_eq!(m.m[1][2], 0.0);
    assert_eq!(m.m[1][3], 0.0);
    assert_eq!(m.m[2][0], 0.0);
    assert_eq!(m.m[2][1], 0.0);
    assert_eq!(m.m[2][2], 0.0);
    assert_eq!(m.m[2][3], 0.0);
    assert_eq!(m.m[3][0], 0.0);
    assert_eq!(m.m[3][1], 0.0);
    assert_eq!(m.m[3][2], 0.0);
    assert_eq!(m.m[3][3], 0.0);
}

impl Mul for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { &self * &rhs }
}

impl<'a> Mul<Matrix> for &'a Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { self * &rhs }
}

impl<'a> Mul<&'a Matrix> for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: &'a Matrix) -> Matrix { &self * rhs }
}

impl<'a, 'b> Mul<&'a Matrix> for &'b Matrix {
    type Output = Matrix;

    fn mul(self, rhs: &'a Matrix) -> Matrix {
        macro_rules! row {
            ($col:expr) => ({
                let x = self.m[$col][0];
                let y = self.m[$col][1];
                let z = self.m[$col][2];
                let w = self.m[$col][3];
                [
                    (rhs.m[0][0]*x)+(rhs.m[1][0]*y)+(rhs.m[2][0]*z)+(rhs.m[3][0]*w),
                    (rhs.m[0][1]*x)+(rhs.m[1][1]*y)+(rhs.m[2][1]*z)+(rhs.m[3][1]*w),
                    (rhs.m[0][2]*x)+(rhs.m[1][2]*y)+(rhs.m[2][2]*z)+(rhs.m[3][2]*w),
                    (rhs.m[0][3]*x)+(rhs.m[1][3]*y)+(rhs.m[2][3]*z)+(rhs.m[3][3]*w),
                ]
            })
        }

        Matrix { m: [ row!(0), row!(1), row!(2), row!(3) ] }
    }
}

impl AsUniformValue for Matrix {
    fn as_uniform_value(&self) -> UniformValue<'static> {
        UniformValue::Mat4(self.m)
    }

    fn matches(ty: &UniformType) -> bool {
        ty == &UniformType::FloatMat4
    }
}
<|endoftext|>


<commit_before>#![crate_id="civet"]
#![crate_type="rlib"]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;

use std::io;
use std::io::{IoResult,util};
use std::collections::HashMap;

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: Request<'a>
}

pub struct Request<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>
}

pub struct CopiedRequest {
    pub headers: HashMap<String, String>,
    pub method: String,
    pub url: String,
    pub http_version: String,
    pub query_string: String,
    pub remote_user: String,
    pub remote_ip: int,
    pub remote_port: int,
    pub is_ssl: bool
}

impl<'a> Request<'a> {
    pub fn copy(&self) -> CopiedRequest {
        let mut headers = HashMap::new();

        for (key, value) in self.headers().iter() {
            headers.insert(key.to_str(), value.to_str());
        }

        CopiedRequest {
            headers: headers,
            method: self.method().to_str(),
            url: self.url().to_str(),
            http_version: self.http_version().to_str(),
            query_string: self.query_string().to_str(),
            remote_user: self.remote_user().to_str(),
            remote_ip: self.remote_ip(),
            remote_port: self.remote_port(),
            is_ssl: self.is_ssl()
        }
    }

    pub fn get_header<S: Str>(&mut self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn count_headers(&self) -> uint {
        self.request_info.num_headers() as uint
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        self.request_info.method()
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        self.request_info.url()
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        self.request_info.http_version()
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        self.request_info.remote_user()
    }

    pub fn remote_ip(&self) -> int {
        self.request_info.remote_ip()
    }

    pub fn remote_port(&self) -> int {
        self.request_info.remote_port()
    }

    pub fn is_ssl(&self) -> bool {
        self.request_info.is_ssl()
    }

    pub fn headers<'a>(&'a self) -> Headers<'a> {
        Headers { conn: self.conn }
    }
}

pub struct Response<S, R> {
    status: S,
    headers: HashMap<String, String>,
    body: R
}

impl<S: ToStatusCode, R: Reader + Send> Response<S, R> {
    pub fn new(status: S,
               headers: HashMap<String, String>,
               body: R) -> Response<S, R> {
        Response { status: status, headers: headers, body: body }
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = Request { conn: conn, request_info: info };
                Ok(Connection {
                    request: request
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for Request<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> Headers<'a> {
    pub fn find<S: Str>(&self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn iter<'a>(&'a self) -> HeaderIterator<'a> {
        HeaderIterator::new(self.conn)
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, &'a str)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, &'a str)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = headers.get(pos);
            self.position += 1;
            header.name().map(|name| (name, header.value().unwrap()))
        }
    }
}

pub type ServerHandler<S, R> = fn(&mut Request) -> IoResult<Response<S, R>>;

#[allow(dead_code)]
pub struct Server(raw::Server);

impl Server {
    pub fn start<S: ToStatusCode, R: Reader + Send>(options: Config,
                                                    handler: ServerHandler<S, R>)
        -> IoResult<Server>
    {
        fn internal_handler<S: ToStatusCode, R: Reader + Send>(
            conn: &mut raw::Connection,
            callback: &ServerHandler<S, R>)
            -> Result<(), ()>
        {
            let mut connection = Connection::new(conn).unwrap();
            let response = (*callback)(&mut connection.request);
            let writer = &mut connection;

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(writer)),
            };
            let (code, string) = try!(status.to_status().map_err(|_| err(writer)));
            try!(write!(writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                try!(write!(writer, "{}: {}\r\n", key, value).map_err(|_| ()));
            }

            try!(write!(writer, "\r\n").map_err(|_| ()));
            try!(util::copy(&mut body, writer).map_err(|_| ()));

            Ok(())
        }

        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(raw::Server::start(options, raw_callback)))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_str())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_str())
    }
}

<commit_msg>Fix types of remote_{addr,ip}<commit_after>#![crate_id="civet"]
#![crate_type="rlib"]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult,util};
use std::collections::HashMap;

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: Request<'a>
}

pub struct Request<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>
}

pub struct CopiedRequest {
    pub headers: HashMap<String, String>,
    pub method: String,
    pub url: String,
    pub http_version: String,
    pub query_string: String,
    pub remote_user: String,
    pub remote_ip: IpAddr,
    pub remote_port: u16,
    pub is_ssl: bool
}

impl<'a> Request<'a> {
    pub fn copy(&self) -> CopiedRequest {
        let mut headers = HashMap::new();

        for (key, value) in self.headers().iter() {
            headers.insert(key.to_str(), value.to_str());
        }

        CopiedRequest {
            headers: headers,
            method: self.method().to_str(),
            url: self.url().to_str(),
            http_version: self.http_version().to_str(),
            query_string: self.query_string().to_str(),
            remote_user: self.remote_user().to_str(),
            remote_ip: self.remote_ip(),
            remote_port: self.remote_port(),
            is_ssl: self.is_ssl()
        }
    }

    pub fn get_header<S: Str>(&mut self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn count_headers(&self) -> uint {
        self.request_info.num_headers() as uint
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        self.request_info.method()
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        self.request_info.url()
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        self.request_info.http_version()
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        self.request_info.remote_user()
    }

    pub fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    pub fn remote_port(&self) -> u16 {
        self.request_info.remote_port() as u16
    }

    pub fn is_ssl(&self) -> bool {
        self.request_info.is_ssl()
    }

    pub fn headers<'a>(&'a self) -> Headers<'a> {
        Headers { conn: self.conn }
    }
}

pub struct Response<S, R> {
    status: S,
    headers: HashMap<String, String>,
    body: R
}

impl<S: ToStatusCode, R: Reader + Send> Response<S, R> {
    pub fn new(status: S,
               headers: HashMap<String, String>,
               body: R) -> Response<S, R> {
        Response { status: status, headers: headers, body: body }
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = Request { conn: conn, request_info: info };
                Ok(Connection {
                    request: request
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for Request<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> Headers<'a> {
    pub fn find<S: Str>(&self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn iter<'a>(&'a self) -> HeaderIterator<'a> {
        HeaderIterator::new(self.conn)
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, &'a str)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, &'a str)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = headers.get(pos);
            self.position += 1;
            header.name().map(|name| (name, header.value().unwrap()))
        }
    }
}

pub type ServerHandler<S, R> = fn(&mut Request) -> IoResult<Response<S, R>>;

#[allow(dead_code)]
pub struct Server(raw::Server);

impl Server {
    pub fn start<S: ToStatusCode, R: Reader + Send>(options: Config,
                                                    handler: ServerHandler<S, R>)
        -> IoResult<Server>
    {
        fn internal_handler<S: ToStatusCode, R: Reader + Send>(
            conn: &mut raw::Connection,
            callback: &ServerHandler<S, R>)
            -> Result<(), ()>
        {
            let mut connection = Connection::new(conn).unwrap();
            let response = (*callback)(&mut connection.request);
            let writer = &mut connection;

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(writer)),
            };
            let (code, string) = try!(status.to_status().map_err(|_| err(writer)));
            try!(write!(writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                try!(write!(writer, "{}: {}\r\n", key, value).map_err(|_| ()));
            }

            try!(write!(writer, "\r\n").map_err(|_| ()));
            try!(util::copy(&mut body, writer).map_err(|_| ()));

            Ok(())
        }

        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(raw::Server::start(options, raw_callback)))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_str())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_str())
    }
}

<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible
//!    manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as
//! extensions to the MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of
//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard
//! libraries. The two are not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
//! which versions of packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version`
//! objects using the `parse` method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1,
//!    minor: 2,
//!    patch: 3,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators
//! to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! If you explicitly need to modify a Version, SemVer also allows you to
//! increment the major, minor, and patch numbers in accordance with the spec.
//!
//! Please note that in order to do this, you must use a mutable Version:
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut bugfix_release = Version::parse("1.0.0").unwrap();
//! bugfix_release.increment_patch();
//!
//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
//! ```
//!
//! When incrementing the minor version number, the patch number resets to zero
//! (in accordance with section 7 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut feature_release = Version::parse("1.4.6").unwrap();
//! feature_release.increment_minor();
//!
//! assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
//! ```
//!
//! Similarly, when incrementing the major version number, the patch and minor
//! numbers reset to zero (in accordance with section 8 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//!
//! let mut chrome_release = Version::parse("41.5.5377").unwrap();
//! chrome_release.increment_major();
//!
//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which
//! are more complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than
//! or equal to 1.0.0:
//!
//! ```{rust}
//! # #![allow(unstable)]
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified
//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
//! `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility
//! for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```
//!
//! **Wildcard requirements** allows parsing of version requirements of the
//! formats `*`, `x.*` and `x.y.*`.
//!
//! ```notrust
//! *     := >=0.0.0
//! 1.*   := >=1.0.0 <2.0.0
//! 1.2.* := >=1.2.0 <1.3.0
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/semver")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate semver_parser;

// Serialization and deserialization support for version numbers
#[cfg(feature = "serde")]
extern crate serde;

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Version, Identifier, SemVerError};
pub use version::Identifier::{Numeric, AlphaNumeric};
pub use version_req::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;
<commit_msg>Use question mark instead of unwrap in examples<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible
//!    manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as
//! extensions to the MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of
//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard
//! libraries. The two are not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
//! which versions of packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version`
//! objects using the `parse` method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1,
//!    minor: 2,
//!    patch: 3,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators
//! to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! If you explicitly need to modify a Version, SemVer also allows you to
//! increment the major, minor, and patch numbers in accordance with the spec.
//!
//! Please note that in order to do this, you must use a mutable Version:
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! fn try_main() -> Result<(), Box<Error>> {
//!
//!     let mut bugfix_release = Version::parse("1.0.0")?;
//!     bugfix_release.increment_patch();
//!
//!     assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     try_main().unwrap();
//! }
//! ```
//!
//! When incrementing the minor version number, the patch number resets to zero
//! (in accordance with section 7 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! fn try_main() -> Result<(), Box<Error>> {
//!
//!    let mut feature_release = Version::parse("1.4.6")?;
//!    feature_release.increment_minor();
//!
//!    assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
//!
//!    Ok(())
//! }
//!
//! fn main() {
//!     try_main().unwrap();
//! }
//! ```
//!
//! Similarly, when incrementing the major version number, the patch and minor
//! numbers reset to zero (in accordance with section 8 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! fn try_main() -> Result<(), Box<Error>> {
//!
//!     let mut chrome_release = Version::parse("41.5.5377")?;
//!     chrome_release.increment_major();
//!
//!     assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     try_main().unwrap();
//! }
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which
//! are more complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than
//! or equal to 1.0.0:
//!
//! ```{rust}
//! # #![allow(unstable)]
//! use semver::Version;
//! use semver::VersionReq;
//! use std::error::Error;
//!
//! fn try_main() -> Result<(), Box<Error>> {
//!
//!     let r = VersionReq::parse(">= 1.0.0")?;
//!     let v = Version::parse("1.0.0")?;
//!
//!     assert!(r.to_string() == ">= 1.0.0".to_string());
//!     assert!(r.matches(&v));
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     try_main().unwrap();
//! }
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified
//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
//! `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility
//! for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```
//!
//! **Wildcard requirements** allows parsing of version requirements of the
//! formats `*`, `x.*` and `x.y.*`.
//!
//! ```notrust
//! *     := >=0.0.0
//! 1.*   := >=1.0.0 <2.0.0
//! 1.2.* := >=1.2.0 <1.3.0
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/semver")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate semver_parser;

// Serialization and deserialization support for version numbers
#[cfg(feature = "serde")]
extern crate serde;

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Identifier, SemVerError, Version};
pub use version::Identifier::{AlphaNumeric, Numeric};
pub use version_req::{ReqParseError, VersionReq};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;
<|endoftext|>


<commit_before>extern crate libc;
use libc::{c_char, c_int, size_t};

pub enum Magic {}

extern "C" {
    pub fn magic_open(flags: c_int) -> *const Magic;
    pub fn magic_close(cookie: *const Magic);
    pub fn magic_error(cookie: *const Magic) -> *const c_char;
    pub fn magic_errno(cookie: *const Magic) -> *const c_int;
    pub fn magic_descriptor(cookie: *const Magic, fd: c_int) -> *const c_char;
    pub fn magic_file(cookie: *const Magic, filename: *const c_char) -> *const c_char;
    pub fn magic_buffer(cookie: *const Magic, buffer: *const u8, length: size_t) -> *const c_char;
    pub fn magic_setflags(cookie: *const Magic, flags: c_int) -> c_int;
    pub fn magic_check(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_compile(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_list(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_load(cookie: *const Magic, filename: *const c_char) -> c_int;
}
<commit_msg>Fix opaque struct definition<commit_after>extern crate libc;
use libc::{c_char, c_int, size_t};

// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
#[repr(C)]
pub struct Magic {
    _data: [u8; 0],
    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

extern "C" {
    pub fn magic_open(flags: c_int) -> *const Magic;
    pub fn magic_close(cookie: *const Magic);
    pub fn magic_error(cookie: *const Magic) -> *const c_char;
    pub fn magic_errno(cookie: *const Magic) -> *const c_int;
    pub fn magic_descriptor(cookie: *const Magic, fd: c_int) -> *const c_char;
    pub fn magic_file(cookie: *const Magic, filename: *const c_char) -> *const c_char;
    pub fn magic_buffer(cookie: *const Magic, buffer: *const u8, length: size_t) -> *const c_char;
    pub fn magic_setflags(cookie: *const Magic, flags: c_int) -> c_int;
    pub fn magic_check(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_compile(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_list(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_load(cookie: *const Magic, filename: *const c_char) -> c_int;
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![doc(html_root_url = "http://arcnmx.github.io/pipe-rs/")]

//! Synchronous in-memory pipe
//!
//! ## Example
//!
//! ```
//! use std::thread::spawn;
//! use std::io::{Read, Write};
//!
//! let (mut read, mut write) = pipe::pipe();
//!
//! let message = "Hello, world!";
//! spawn(move || write.write_all(message.as_bytes()).unwrap());
//!
//! let mut s = String::new();
//! read.read_to_string(&mut s).unwrap();
//!
//! assert_eq!(&s, message);
//! ```

#[cfg(feature="readwrite")]
extern crate readwrite;
extern crate crossbeam_channel;

use crossbeam_channel::{Sender, Receiver};
use std::io::{self, Read, Write};
use std::cmp::min;

/// The `Read` end of a pipe (see `pipe()`)
pub struct PipeReader(Receiver<Vec<u8>>, Vec<u8>);

/// The `Write` end of a pipe (see `pipe()`)
#[derive(Clone)]
pub struct PipeWriter(Sender<Vec<u8>>);

/// Creates a synchronous memory pipe
pub fn pipe() -> (PipeReader, PipeWriter) {
    let (tx, rx) = crossbeam_channel::bounded(0);

    (PipeReader(rx, Vec::new()), PipeWriter(tx))
}

/// Creates a pair of pipes for bidirectional communication, a bit like UNIX's `socketpair(2)`.
#[cfg(feature="readwrite")]
pub fn bipipe() -> (readwrite::ReadWrite<PipeReader, PipeWriter>, readwrite::ReadWrite<PipeReader, PipeWriter>) {
    let (r1,w1) = pipe();
    let (r2,w2) = pipe();
    ((r1,w2).into(), (r2,w1).into())
}

impl PipeWriter {
    /// Extracts the inner `SyncSender` from the writer
    pub fn into_inner(self) -> Sender<Vec<u8>> {
        self.0
    }
}

impl PipeReader {
    /// Extracts the inner `Receiver` from the writer, and any pending buffered data
    pub fn into_inner(self) -> (Receiver<Vec<u8>>, Vec<u8>) {
        (self.0, self.1)
    }
}

impl Read for PipeReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        while self.1.is_empty() {
            match self.0.recv() {
                // The only existing error from mpsc is EOF
                Err(_) => return Ok(0),
                Ok(data) => self.1 = data,
            }
        }

        let len = min(buf.len(), self.1.len());
        buf[..len].copy_from_slice(&self.1[..len]);
        self.1.drain(..len);
        Ok(len)
    }
}

impl Write for PipeWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let data = buf.to_vec();

        self.0.send(data)
            .map(|_| buf.len())
            .map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "pipe reader has been dropped"))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::thread::spawn;
    use std::io::{Read, Write};
    use super::*;

    #[test]
    fn pipe_reader() {
        let i = b"hello there";
        let mut o = Vec::with_capacity(i.len());
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            w.write_all(&i[..5]).unwrap();
            w.write_all(&i[5..]).unwrap();
            drop(w);
        });

        r.read_to_end(&mut o).unwrap();
        assert_eq!(i, &o[..]);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_writer_fail() {
        let i = b"hi";
        let (r, mut w) = pipe();
        let guard = spawn(move || {
            drop(r);
        });

        assert!(w.write_all(i).is_err());

        guard.join().unwrap();
    }

    #[test]
    fn small_reads() {
        let block_cnt = 20;
        const BLOCK: usize = 20;
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            for _ in 0..block_cnt {
                let data = &[0; BLOCK];
                w.write_all(data).unwrap();
            }
        });

        let mut buff = [0; BLOCK / 2];
        let mut read = 0;
        while let Ok(size) = r.read(&mut buff) {
            // 0 means EOF
            if size == 0 {
                break;
            }
            read += size;
        }
        assert_eq!(block_cnt * BLOCK, read);

        guard.join().unwrap();
    }
}
<commit_msg>impl BufRead<commit_after>#![deny(missing_docs)]
#![doc(html_root_url = "http://arcnmx.github.io/pipe-rs/")]

//! Synchronous in-memory pipe
//!
//! ## Example
//!
//! ```
//! use std::thread::spawn;
//! use std::io::{Read, Write};
//!
//! let (mut read, mut write) = pipe::pipe();
//!
//! let message = "Hello, world!";
//! spawn(move || write.write_all(message.as_bytes()).unwrap());
//!
//! let mut s = String::new();
//! read.read_to_string(&mut s).unwrap();
//!
//! assert_eq!(&s, message);
//! ```

#[cfg(feature="readwrite")]
extern crate readwrite;
extern crate crossbeam_channel;

use crossbeam_channel::{Sender, Receiver};
use std::io::{self, BufRead, Read, Write};
use std::cmp::min;

/// The `Read` end of a pipe (see `pipe()`)
pub struct PipeReader(Receiver<Vec<u8>>, Vec<u8>);

/// The `Write` end of a pipe (see `pipe()`)
#[derive(Clone)]
pub struct PipeWriter(Sender<Vec<u8>>);

/// Creates a synchronous memory pipe
pub fn pipe() -> (PipeReader, PipeWriter) {
    let (tx, rx) = crossbeam_channel::bounded(0);

    (PipeReader(rx, Vec::new()), PipeWriter(tx))
}

/// Creates a pair of pipes for bidirectional communication, a bit like UNIX's `socketpair(2)`.
#[cfg(feature="readwrite")]
pub fn bipipe() -> (readwrite::ReadWrite<PipeReader, PipeWriter>, readwrite::ReadWrite<PipeReader, PipeWriter>) {
    let (r1,w1) = pipe();
    let (r2,w2) = pipe();
    ((r1,w2).into(), (r2,w1).into())
}

impl PipeWriter {
    /// Extracts the inner `SyncSender` from the writer
    pub fn into_inner(self) -> Sender<Vec<u8>> {
        self.0
    }
}

impl PipeReader {
    /// Extracts the inner `Receiver` from the writer, and any pending buffered data
    pub fn into_inner(self) -> (Receiver<Vec<u8>>, Vec<u8>) {
        (self.0, self.1)
    }
}

impl BufRead for PipeReader {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        while self.1.is_empty() {
            match self.0.recv() {
                // The only existing error is EOF
                Err(_) => break,
                Ok(data) => self.1 = data,
            }
        }

        return Ok(&self.1);
    }

    fn consume(&mut self, amt: usize) {
        self.1.drain(..amt);
    }
}

impl Read for PipeReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        let internal = self.fill_buf()?;

        let len = min(buf.len(), internal.len());
        if len > 0 {
            buf[..len].copy_from_slice(&internal[..len]);
            self.consume(len);
        }
        Ok(len)
    }
}

impl Write for PipeWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let data = buf.to_vec();

        self.0.send(data)
            .map(|_| buf.len())
            .map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "pipe reader has been dropped"))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::thread::spawn;
    use std::io::{Read, Write};
    use super::*;

    #[test]
    fn pipe_reader() {
        let i = b"hello there";
        let mut o = Vec::with_capacity(i.len());
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            w.write_all(&i[..5]).unwrap();
            w.write_all(&i[5..]).unwrap();
            drop(w);
        });

        r.read_to_end(&mut o).unwrap();
        assert_eq!(i, &o[..]);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_writer_fail() {
        let i = b"hi";
        let (r, mut w) = pipe();
        let guard = spawn(move || {
            drop(r);
        });

        assert!(w.write_all(i).is_err());

        guard.join().unwrap();
    }

    #[test]
    fn small_reads() {
        let block_cnt = 20;
        const BLOCK: usize = 20;
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            for _ in 0..block_cnt {
                let data = &[0; BLOCK];
                w.write_all(data).unwrap();
            }
        });

        let mut buff = [0; BLOCK / 2];
        let mut read = 0;
        while let Ok(size) = r.read(&mut buff) {
            // 0 means EOF
            if size == 0 {
                break;
            }
            read += size;
        }
        assert_eq!(block_cnt * BLOCK, read);

        guard.join().unwrap();
    }
}
<|endoftext|>


<commit_before><commit_msg>Implement edge scoring. Refactor<commit_after><|endoftext|>


<commit_before>#![cfg(target_arch="x86_64")]

#![feature(const_fn)]
#![feature(asm)]
#![feature(associated_consts)]
#![no_std]
#![cfg_attr(test, allow(unused_features))]

pub use address::{VirtualAddress, PhysicalAddress};

#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate raw_cpuid;

extern crate bit_field;

pub mod address;

macro_rules! bit {
    ( $x:expr ) => {
        1 << $x
    };
}

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $flag:ident) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            self.contains($flag)
        }
    )
}

macro_rules! is_bit_set {
    ($field:expr, $bit:expr) => (
        $field & (1 << $bit) > 0
    )
}

macro_rules! check_bit_fn {
    ($doc:meta, $fun:ident, $field:ident, $bit:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            is_bit_set!(self.$field, $bit)
        }
    )
}

pub mod time;
pub mod irq;
pub mod paging;
pub mod task;
pub mod syscall;
pub mod sgx;
pub mod control_regs;
pub mod dtables;
pub mod io;
pub mod msr;
pub mod flags;
pub mod segmentation;
pub mod tlb;

pub mod cpuid {
    pub use raw_cpuid::*;
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PrivilegeLevel {
    Ring0 = 0,
    Ring1 = 1,
    Ring2 = 2,
    Ring3 = 3,
}

#[inline(always)]
pub unsafe fn halt() {
    asm!("hlt" :::: "volatile");
}
<commit_msg>Warn on missing docs<commit_after>#![cfg(target_arch="x86_64")]

#![warn(missing_docs)]

#![feature(const_fn)]
#![feature(asm)]
#![feature(associated_consts)]
#![no_std]
#![cfg_attr(test, allow(unused_features))]

pub use address::{VirtualAddress, PhysicalAddress};

#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate raw_cpuid;

extern crate bit_field;

pub mod address;

macro_rules! bit {
    ( $x:expr ) => {
        1 << $x
    };
}

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $flag:ident) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            self.contains($flag)
        }
    )
}

macro_rules! is_bit_set {
    ($field:expr, $bit:expr) => (
        $field & (1 << $bit) > 0
    )
}

macro_rules! check_bit_fn {
    ($doc:meta, $fun:ident, $field:ident, $bit:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            is_bit_set!(self.$field, $bit)
        }
    )
}

pub mod time;
pub mod irq;
pub mod paging;
pub mod task;
pub mod syscall;
pub mod sgx;
pub mod control_regs;
pub mod dtables;
pub mod io;
pub mod msr;
pub mod flags;
pub mod segmentation;
pub mod tlb;

pub mod cpuid {
    pub use raw_cpuid::*;
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PrivilegeLevel {
    Ring0 = 0,
    Ring1 = 1,
    Ring2 = 2,
    Ring3 = 3,
}

#[inline(always)]
pub unsafe fn halt() {
    asm!("hlt" :::: "volatile");
}
<|endoftext|>


<commit_before>use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::eq;
use std::ptr::null;
use std::ptr::null_mut;

const _PAGE_SIZE: usize = 0x1000;

pub struct _Page<'a> {
    current_page: *mut _Page<'a>,
    next_object_offset: i32,
    exclusive_pages: i32,
}

impl<'a> _Page<'a> {
    pub fn reset(&mut self) {
        unsafe {
            *(self.get_extension_page_location() as *mut *const _Page) = null();
        }
        self.next_object_offset = 0;
        self.exclusive_pages = 0;
        self.current_page = &mut *self;
    }

    pub fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    fn get_extension_page_location(&self) -> usize {
        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = self_location + _PAGE_SIZE;

        // Go back one pointer size
        location_behind_page - size_of::<*const _Page>()
    }

    fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    fn get_next_exclusive_page_location(&self) -> usize {
        self.get_extension_page_location()
            - (self.exclusive_pages as usize + 1) * size_of::<*const _Page>()
    }

    pub fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if !eq(self, self.current_page) {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                let new_object = (*self.current_page).allocate_raw(size, align);

                // Possibly our current page was also full so we propagate back the new current page
                let allocating_page = _Page::get_page(new_object);
                if !eq(allocating_page, self.current_page) && (!allocating_page.is_oversized()) {
                    self.current_page = allocating_page;
                }
                return new_object;
            }
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let next_location = (location + align - 1) & !(align - 1);
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8;
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        if size_of::<_Page>() + size + size_of::<*const _Page>() > _PAGE_SIZE {
            if self.get_next_location() >= self.get_extension_page_location() {
                // Allocate an extension page with default size
                let extension_page = self.allocate_extension_page();

                // Try again with the new extension page
                return extension_page.allocate_raw(size, align);
            }

            unsafe {
                // We allocate oversized objects directly.
                let memory = alloc(Layout::from_size_align_unchecked(
                    size + size_of::<_Page>(),
                    _PAGE_SIZE,
                ));

                // Initialize a _Page object at the page start
                let page = memory as *mut _Page<'a>;

                // Oversized pages have no current_page
                (*page).current_page = null_mut();

                // Set the size since we will need it when deallocating
                (*page).next_object_offset = (size % 0x100000000) as i32;
                (*page).exclusive_pages = (size / 0x100000000) as i32;

                *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
                self.exclusive_pages += 1;
                return page.offset(1) as *mut u8;
            }
        }

        // So we're not oversized. Create extension page and let it allocate.
        self.allocate_extension_page().allocate_raw(size, align)
    }

    fn allocate_extension_page(&mut self) -> &'a mut _Page<'a> {
        unsafe {
            let page = _Page::allocate_page();
            *(self.get_extension_page_location() as *mut *const _Page) = page;
            self.current_page = page;
            &mut *page
        }
    }

    fn allocate_page() -> *mut _Page<'a> {
        unsafe {
            let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
            let page = memory as *mut _Page<'a>;
            (*page).reset();
            page
        }
    }

    pub fn allocate_exclusive_page(&mut self) -> &'a mut _Page<'a> {
        if !eq(self, self.current_page) {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                return (*self.current_page).allocate_exclusive_page();
            }
        }

        // Check first whether we need an ordinary extension
        if self.get_next_location() >= self.get_next_exclusive_page_location() {
            // Allocate an extension page with default size
            return self.allocate_extension_page().allocate_exclusive_page();
        }

        let page = _Page::allocate_page();
        unsafe {
            *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
            self.exclusive_pages += 1;
            &mut *page
        }
    }

    pub fn extend(&mut self, top: usize, size: usize) -> bool {
        if top != self.get_next_location() {
            return false;
        }

        let new_top = top + size;
        if new_top > self.get_next_exclusive_page_location() {
            return false;
        }
        self.set_next_location(new_top);

        true
    }

    pub fn deallocate_extensions(&mut self) {
        let mut page: *mut _Page<'a> = self;
        unsafe {
            while !page.is_null() {
                let extension_location = (*page).get_extension_page_location();
                for i in 1..(*page).exclusive_pages {
                    let mut exclusive_page = &mut *((extension_location
                        - (i as usize * size_of::<*const _Page> as usize))
                        as *mut _Page<'a>);
                    if !exclusive_page.is_oversized() {
                        exclusive_page.deallocate_extensions();
                    }
                    exclusive_page.forget();
                }

                if !eq(page, self) {
                    (*page).forget();
                }

                page = extension_location as *mut _Page<'a>;
            }
        }
    }

    pub fn forget(&self) {
        let size = if self.current_page == null_mut() {
            self.next_object_offset as usize + self.exclusive_pages as usize * 0x100000000
        } else {
            _PAGE_SIZE
        };
        unsafe {
            dealloc(
                self as *const _Page as *mut u8,
                Layout::from_size_align_unchecked(size, _PAGE_SIZE),
            )
        }
    }

    pub fn reclaim_array(&mut self, address: usize) -> bool {
        unsafe {
            let mut page: *mut _Page<'a> = self;
            while !page.is_null() {
                if (*page).deallocate_exclusive_page(&mut *(address as *mut _Page<'a>)) {
                    return true;
                }
                page = (*page).get_extension_page_location() as *mut _Page<'a>;
            }
        }

        // If we arrive here, we have a memory leak.
        false
    }

    pub fn get_page(address: *mut u8) -> &'a mut _Page<'a> {
        unsafe { &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page) }
    }

    fn deallocate_exclusive_page(&mut self, page: &'a mut _Page<'a>) -> bool {
        // Find the extension Page pointer
        let mut extension_location = self.get_extension_page_location() - size_of::<*const _Page>();
        let next_extension_page_location = self.get_next_exclusive_page_location();
        while extension_location > next_extension_page_location {
            if eq(extension_location as *const _Page, page) {
                break;
            }
            extension_location -= size_of::<*const _Page>();
        }

        // Report if we could not find it
        if extension_location == next_extension_page_location {
            return false;
        }

        // Shift the remaining array one position up
        while extension_location > next_extension_page_location {
            let pp_page = extension_location as *mut *const _Page;
            unsafe {
                *pp_page = *(pp_page.offset(-1));
            }
            extension_location -= size_of::<*const _Page>();
        }

        // Make room for one more extension
        self.exclusive_pages -= 1;
        page.forget();

        true
    }
}

#[test]
fn test_page() {
    unsafe {
        // Allocate a page
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
        assert_ne!(memory, null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, 0);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!((*(page.current_page)).next_object_offset, 0);
        assert_eq!((*(page.current_page)).exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);
    }
}
<commit_msg>removed 'a, some fixes and tests<commit_after>use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const _PAGE_SIZE: usize = 0x1000;

pub struct _Page {
    current_page: *mut _Page,
    next_object_offset: i32,
    exclusive_pages: i32,
}

impl _Page {
    pub fn reset(&mut self) {
        unsafe {
            *(self.get_extension_page_location()) = null_mut();
        }
        self.next_object_offset = size_of::<_Page>() as i32;
        self.exclusive_pages = 0;
        self.current_page = &mut *self;
    }

    pub fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    fn get_extension_page_location(&self) -> *mut *mut _Page {
        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = (self_location + _PAGE_SIZE) as *mut *mut _Page;

        // Go back one pointer size
        unsafe { location_behind_page.offset(-1) }
    }

    fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    fn get_next_exclusive_page_location(&self) -> *mut *mut _Page {
        unsafe {
            self.get_extension_page_location()
                .offset(-(self.exclusive_pages as isize + 1))
        }
    }

    pub fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if self as *mut _Page != self.current_page {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                let new_object = (*self.current_page).allocate_raw(size, align);

                // Possibly our current page was also full so we propagate back the new current page
                let allocating_page = _Page::get_page(new_object);
                if allocating_page != self.current_page && (!(*allocating_page).is_oversized()) {
                    self.current_page = allocating_page;
                }
                return new_object;
            }
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let aligned_location = (location + align - 1) & !(align - 1);
        let next_location = aligned_location + size;
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8;
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        if size_of::<_Page>() + size + size_of::<*mut *mut _Page>() > _PAGE_SIZE {
            if self.get_next_location() >= self.get_next_exclusive_page_location() as usize {
                // Allocate an extension page and try again with it
                unsafe {
                    return (*self.allocate_extension_page()).allocate_raw(size, align);
                }
            }

            unsafe {
                // We allocate oversized objects directly.
                let memory = alloc(Layout::from_size_align_unchecked(
                    size + size_of::<_Page>(),
                    _PAGE_SIZE,
                ));

                // Initialize a _Page object at the page start
                let page = memory as *mut _Page;

                // Oversized pages have no current_page
                (*page).current_page = null_mut();

                // Set the size since we will need it when deallocating
                (*page).next_object_offset = (size % 0x100000000) as i32;
                (*page).exclusive_pages = (size / 0x100000000) as i32;

                *(self.get_next_exclusive_page_location()) = page;
                self.exclusive_pages += 1;
                return page.offset(1) as *mut u8;
            }
        }

        // So we're not oversized. Create extension page and let it allocate.
        unsafe { (*self.allocate_extension_page()).allocate_raw(size, align) }
    }

    fn allocate_extension_page(&mut self) -> *mut _Page {
        unsafe {
            let page = _Page::allocate_page();
            *(self.get_extension_page_location()) = page;
            self.current_page = page;
            &mut *page
        }
    }

    fn allocate_page() -> *mut _Page {
        unsafe {
            let page =
                alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE)) as *mut _Page;
            (*page).reset();
            page
        }
    }

    pub fn allocate_exclusive_page(&mut self) -> *mut _Page {
        unsafe {
            if self as *mut _Page != self.current_page {
                // We're already known to be full, so we delegate to the current page
                return (*self.current_page).allocate_exclusive_page();
            }

            // Check first whether we need an ordinary extension
            if self.get_next_location() as usize >= self.get_next_exclusive_page_location() as usize
            {
                // Allocate an extension page with default size
                return (*self.allocate_extension_page()).allocate_exclusive_page();
            }

            let page = _Page::allocate_page();
            *(self.get_next_exclusive_page_location()) = page;
            self.exclusive_pages += 1;
            &mut *page
        }
    }

    pub fn extend(&mut self, top: usize, size: usize) -> bool {
        if top != self.get_next_location() {
            return false;
        }

        let new_top = top + size;
        if new_top > self.get_next_exclusive_page_location() as usize {
            return false;
        }
        self.set_next_location(new_top);

        true
    }

    pub fn deallocate_extensions(&mut self) {
        let mut page: *mut _Page = self;
        unsafe {
            while !page.is_null() {
                let extension_pointer = (*page).get_extension_page_location();
                for i in 1..(*page).exclusive_pages {
                    let mut exclusive_page = &mut **(extension_pointer.offset(-(i as isize)));
                    if !exclusive_page.is_oversized() {
                        exclusive_page.deallocate_extensions();
                    }
                    exclusive_page.forget();
                }

                if page != self as *mut _Page {
                    (*page).forget();
                }

                page = *extension_pointer;
            }
        }
    }

    pub fn forget(&self) {
        let size = if self.current_page == null_mut() {
            self.next_object_offset as usize + self.exclusive_pages as usize * 0x100000000
        } else {
            _PAGE_SIZE
        };
        unsafe {
            dealloc(
                self as *const _Page as *mut u8,
                Layout::from_size_align_unchecked(size, _PAGE_SIZE),
            )
        }
    }

    pub fn reclaim_array(&mut self, address: usize) -> bool {
        unsafe {
            let mut page: *mut _Page = self;
            while !page.is_null() {
                if (*page).deallocate_exclusive_page(address as *mut _Page) {
                    return true;
                }
                page = *(*page).get_extension_page_location();
            }
        }

        // If we arrive here, we have a memory leak.
        false
    }

    pub fn get_page(address: *mut u8) -> *mut _Page {
        unsafe { &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page) }
    }

    fn deallocate_exclusive_page(&mut self, page: *mut _Page) -> bool {
        unsafe {
            // Find the extension Page pointer
            let mut extension_pointer = self.get_extension_page_location().offset(-1);
            let next_extension_page_location = self.get_next_exclusive_page_location();
            while extension_pointer > next_extension_page_location {
                if *extension_pointer == page {
                    break;
                }
                extension_pointer = extension_pointer.offset(-1);
            }

            // Report if we could not find it
            if extension_pointer == next_extension_page_location {
                return false;
            }

            // Shift the remaining array one position up
            while extension_pointer > next_extension_page_location {
                let pp_page = extension_pointer;
                *pp_page = *(pp_page.offset(-1));
                extension_pointer = extension_pointer.offset(-1);
            }
        }

        // Make room for one more extension
        self.exclusive_pages -= 1;
        unsafe {
            (*page).forget();
        }

        true
    }
}

#[test]
fn test_page() {
    unsafe {
        // Allocate a page
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
        assert_ne!(memory, null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, size_of::<_Page>() as i32);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);
        assert_eq!(page as *mut _Page, page.current_page);

        {
            let extension_page_location = page.get_extension_page_location();
            assert_eq!(
                extension_page_location as usize,
                page as *const _Page as usize + _PAGE_SIZE - size_of::<*mut *mut _Page>()
            );
        }

        {
            let mut location = page.get_next_location();
            assert_eq!(
                location as usize,
                page as *const _Page as usize + size_of::<_Page>()
            );

            let mut memory = page.allocate_raw(1, 1);
            location += 1;
            assert_eq!(page.get_next_location(), location);
            *memory = 42;
            memory = page.allocate_raw(1, 2);
            location += 2;
            assert_eq!(page.get_next_location(), location);
            *memory = 43;
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::to_str::ToStr;
use std::os::pipe;
use std::io::{Open, Write};
use std::io::fs::{mkdir, File};
use std::io::pipe::PipeStream;
use std::io::stdio::{stdout, stderr};

use argparse::{ArgumentParser, Store, List};

use super::env::Environ;
use super::config::Config;
use super::linux::{make_namespace, change_root, bind_mount, mount_pseudofs};
use super::linux::{execute, forkme, wait_process};
use libc::funcs::posix88::unistd::getuid;

fn mount_all(root: &Path, mount_dir: &Path, project_root: &Path)
    -> Result<(), String>
{
    let vagga_marker = mount_dir.join_many(["tmp", ".vagga"]);
    try!(bind_mount(root, mount_dir, false));
    try!(bind_mount(&Path::new("/sys"), &mount_dir.join("sys"), false));
    // TODO(tailhook) use dev in /var/lib/container-dev
    try!(bind_mount(&Path::new("/dev"), &mount_dir.join("dev"), false));
    try!(bind_mount(project_root, &mount_dir.join("work"), true));
    try!(mount_pseudofs("proc", &mount_dir.join("proc"), ""));
    // TODO(tailhook) allow customize size of tmpfs
    try!(mount_pseudofs("tmpfs", &mount_dir.join("tmp"),
                        "size=102400k,mode=1777"));
    try!(ensure_dir(&vagga_marker));
    try!(bind_mount(&vagga_marker,
                    &mount_dir.join_many(["work", ".vagga"]),
                    false));
    match File::open_mode(&vagga_marker.join("CONTAINED.txt"), Open, Write)
        .write_line("You are running in vagga container.") {
        Ok(()) => {}
        Err(e) => return Err(format!("Can't write CONTAINED.txt: {}", e)),
    }
    return Ok(());
}

fn ensure_dir(p: &Path) -> Result<(),String> {
    if p.exists() {
        return Ok(());
    }
    return mkdir(p, io::UserRWX).map_err(|e| { e.to_str() });
}

pub fn run_chroot(env: &Environ, container_root: &Path, mount_dir: &Path,
    command: &String, args: &Vec<String>)
    -> Result<(),String>
{
    try!(mount_all(container_root, mount_dir, &env.project_root));
    try!(change_root(mount_dir));
    // TODO(tailhook) set environment from config
    let environ = vec!("PATH=/bin:/usr/bin:/usr/local/bin".to_string());
    try!(execute(command, args, &environ));
    unreachable!();
}

pub fn run_user_command(env: &Environ, config: &Config,
    cmdname: &String, args: Vec<String>)
    -> Result<int, String>
{
    let command = match config.commands.find(cmdname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find command {} in config",
                               cmdname));
        }
    };
    let cname = match command.container {
        Some(ref name) => name.clone(),
        None => unimplemented!(),
    };
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} for command {}",
                               command.container, cmdname));
        }
    };
    return match command.run {
        Some(ref cmdline) => _run(env, config, &cname,
            &"/bin/sh".to_string(),
            &(vec!("-c".to_string(), cmdline.clone()) + args.slice_from(1))),
        None => unimplemented!()
    }
}

pub fn run_command(env: &Environ, config: &Config, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut command = "".to_string();
    let mut cmdargs = Vec::new();
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut command)
            .add_argument("command", box Store::<String>,
                "A command to run inside container")
            .required();
        ap.refer(&mut cmdargs)
            .add_argument("arguments", box List::<String>,
                "Arguments for the command")
            .required();
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} in config",
                               cname));
        }
    };
    _run(env, config, &cname, &command, &cmdargs)
}

pub fn _run(env: &Environ, config: &Config, container: &String,
    command: &String, cmdargs: &Vec<String>)
    -> Result<int, String>
{
    info!("Running {}: {} {}", container, command, cmdargs);
    let container_dir = env.project_root.join_many(
        [".vagga", container.as_slice()]);
    let container_root = container_dir.join("root");
    let uid = unsafe { getuid() };

    for dir in ["proc", "sys", "dev", "work", "tmp"].iter() {
        try!(ensure_dir(&container_root.join(*dir)));
    }

    let mount_dir = env.project_root.join_many([".vagga", "mnt"]);
    try!(ensure_dir(&mount_dir));
    try!(make_namespace());

    let mut pipe = match PipeStream::pair() {
        Ok(pipe) => pipe,
        Err(x) => return Err(format!("Can't create pipe: {}", x)),
    };

    let pid = try!(forkme());
    if pid == 0 {
        let mut buf: [u8,..1] = [0];
        match pipe.reader.read(buf) {
            Ok(_) => {}
            Err(x) => return Err(format!("Can't read from pipe: {}", x)),
        }
        drop(pipe);
        try!(run_chroot(env, &container_root, &mount_dir, command, cmdargs));
        unreachable!();
    } else {
        // TODO(tailhook) set uid map from config
        let uid_map = format!("0 {} 1", uid);
        debug!("Writing uid_map: {}", uid_map);
        match File::open_mode(&Path::new("/proc")
                          .join(pid.to_str())
                          .join("uid_map"), Open, Write)
                .write_str(uid_map.as_slice()) {
            Ok(()) => {}
            Err(e) => return Err(format!(
                "Error writing uid mapping: {}", e)),
        }

        match pipe.writer.write_char('x') {
            Ok(_) => {}
            Err(e) => return Err(format!(
                "Error writing to pipe: {}", e)),
        }
        drop(pipe);

        return wait_process(pid);
    }
}
<commit_msg>Add fake HOME to environment<commit_after>use std::io;
use std::to_str::ToStr;
use std::os::pipe;
use std::io::{Open, Write};
use std::io::fs::{mkdir, File};
use std::io::pipe::PipeStream;
use std::io::stdio::{stdout, stderr};

use argparse::{ArgumentParser, Store, List};

use super::env::Environ;
use super::config::Config;
use super::linux::{make_namespace, change_root, bind_mount, mount_pseudofs};
use super::linux::{execute, forkme, wait_process};
use libc::funcs::posix88::unistd::getuid;

fn mount_all(root: &Path, mount_dir: &Path, project_root: &Path)
    -> Result<(), String>
{
    let vagga_marker = mount_dir.join_many(["tmp", ".vagga"]);
    try!(bind_mount(root, mount_dir, false));
    try!(bind_mount(&Path::new("/sys"), &mount_dir.join("sys"), false));
    // TODO(tailhook) use dev in /var/lib/container-dev
    try!(bind_mount(&Path::new("/dev"), &mount_dir.join("dev"), false));
    try!(bind_mount(project_root, &mount_dir.join("work"), true));
    try!(mount_pseudofs("proc", &mount_dir.join("proc"), ""));
    // TODO(tailhook) allow customize size of tmpfs
    try!(mount_pseudofs("tmpfs", &mount_dir.join("tmp"),
                        "size=102400k,mode=1777"));
    try!(ensure_dir(&vagga_marker));
    try!(bind_mount(&vagga_marker,
                    &mount_dir.join_many(["work", ".vagga"]),
                    false));
    match File::open_mode(&vagga_marker.join("CONTAINED.txt"), Open, Write)
        .write_line("You are running in vagga container.") {
        Ok(()) => {}
        Err(e) => return Err(format!("Can't write CONTAINED.txt: {}", e)),
    }
    return Ok(());
}

fn ensure_dir(p: &Path) -> Result<(),String> {
    if p.exists() {
        return Ok(());
    }
    return mkdir(p, io::UserRWX).map_err(|e| { e.to_str() });
}

pub fn run_chroot(env: &Environ, container_root: &Path, mount_dir: &Path,
    command: &String, args: &Vec<String>)
    -> Result<(),String>
{
    try!(mount_all(container_root, mount_dir, &env.project_root));
    try!(change_root(mount_dir));
    // TODO(tailhook) set environment from config
    let environ = vec!(
        "PATH=/bin:/usr/bin:/usr/local/bin".to_string(),
        "HOME=/non-existent".to_string(),
        );
    try!(execute(command, args, &environ));
    unreachable!();
}

pub fn run_user_command(env: &Environ, config: &Config,
    cmdname: &String, args: Vec<String>)
    -> Result<int, String>
{
    let command = match config.commands.find(cmdname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find command {} in config",
                               cmdname));
        }
    };
    let cname = match command.container {
        Some(ref name) => name.clone(),
        None => unimplemented!(),
    };
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} for command {}",
                               command.container, cmdname));
        }
    };
    return match command.run {
        Some(ref cmdline) => _run(env, config, &cname,
            &"/bin/sh".to_string(),
            &(vec!("-c".to_string(), cmdline.clone()) + args.slice_from(1))),
        None => unimplemented!()
    }
}

pub fn run_command(env: &Environ, config: &Config, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut command = "".to_string();
    let mut cmdargs = Vec::new();
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut command)
            .add_argument("command", box Store::<String>,
                "A command to run inside container")
            .required();
        ap.refer(&mut cmdargs)
            .add_argument("arguments", box List::<String>,
                "Arguments for the command")
            .required();
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} in config",
                               cname));
        }
    };
    _run(env, config, &cname, &command, &cmdargs)
}

pub fn _run(env: &Environ, config: &Config, container: &String,
    command: &String, cmdargs: &Vec<String>)
    -> Result<int, String>
{
    info!("Running {}: {} {}", container, command, cmdargs);
    let container_dir = env.project_root.join_many(
        [".vagga", container.as_slice()]);
    let container_root = container_dir.join("root");
    let uid = unsafe { getuid() };

    for dir in ["proc", "sys", "dev", "work", "tmp"].iter() {
        try!(ensure_dir(&container_root.join(*dir)));
    }

    let mount_dir = env.project_root.join_many([".vagga", "mnt"]);
    try!(ensure_dir(&mount_dir));
    try!(make_namespace());

    let mut pipe = match PipeStream::pair() {
        Ok(pipe) => pipe,
        Err(x) => return Err(format!("Can't create pipe: {}", x)),
    };

    let pid = try!(forkme());
    if pid == 0 {
        let mut buf: [u8,..1] = [0];
        match pipe.reader.read(buf) {
            Ok(_) => {}
            Err(x) => return Err(format!("Can't read from pipe: {}", x)),
        }
        drop(pipe);
        try!(run_chroot(env, &container_root, &mount_dir, command, cmdargs));
        unreachable!();
    } else {
        // TODO(tailhook) set uid map from config
        let uid_map = format!("0 {} 1", uid);
        debug!("Writing uid_map: {}", uid_map);
        match File::open_mode(&Path::new("/proc")
                          .join(pid.to_str())
                          .join("uid_map"), Open, Write)
                .write_str(uid_map.as_slice()) {
            Ok(()) => {}
            Err(e) => return Err(format!(
                "Error writing uid mapping: {}", e)),
        }

        match pipe.writer.write_char('x') {
            Ok(_) => {}
            Err(e) => return Err(format!(
                "Error writing to pipe: {}", e)),
        }
        drop(pipe);

        return wait_process(pid);
    }
}
<|endoftext|>